diff options
author | Alan Hourihane <[email protected]> | 2008-11-20 13:44:13 +0000 |
---|---|---|
committer | Alan Hourihane <[email protected]> | 2008-11-20 13:44:13 +0000 |
commit | ef2bf418b45c7966e9fe78359058b8d44f570be1 (patch) | |
tree | c0bc3be44bae336ca4c9133ffb2529c8d99bbc0f /src/mesa/shader/slang | |
parent | 4f3dcf3864c3cbd8a6ebc6af38e53d57e4d421d6 (diff) | |
parent | b6bb5e09e0ad1f61f96c65bbc870bd493df12f1a (diff) |
Merge commit 'origin/master' into gallium-0.2
Diffstat (limited to 'src/mesa/shader/slang')
-rw-r--r-- | src/mesa/shader/slang/library/slang_shader.syn | 29 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_codegen.c | 34 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_compile.c | 292 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_emit.c | 413 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_ir.c | 50 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_ir.h | 57 | ||||
-rw-r--r-- | src/mesa/shader/slang/slang_vartable.h | 10 |
7 files changed, 557 insertions, 328 deletions
diff --git a/src/mesa/shader/slang/library/slang_shader.syn b/src/mesa/shader/slang/library/slang_shader.syn index cbfbda651af..47245e0d878 100644 --- a/src/mesa/shader/slang/library/slang_shader.syn +++ b/src/mesa/shader/slang/library/slang_shader.syn @@ -837,10 +837,8 @@ parameter_type_specifier_3 * <init_declarator_list> ::= <single_declaration> * | <init_declarator_list> "," <identifier> * | <init_declarator_list> "," <identifier> "[" "]" - * | <init_declarator_list> "," <identifier> "[" - * <constant_expression> "]" - * | <init_declarator_list> "," <identifier> "=" - * <initializer> + * | <init_declarator_list> "," <identifier> "[" <constant_expression> "]" + * | <init_declarator_list> "," <identifier> "=" <initializer> */ init_declarator_list single_declaration .and .loop init_declarator_list_1 .emit DECLARATOR_NEXT .and @@ -860,10 +858,9 @@ init_declarator_list_5 * <single_declaration> ::= <fully_specified_type> * | <fully_specified_type> <identifier> * | <fully_specified_type> <identifier> "[" "]" - * | <fully_specified_type> <identifier> "[" - * <constant_expression> "]" + * | <fully_specified_type> <identifier> "[" <constant_expression> "]" * | <fully_specified_type> <identifier> "=" <initializer> -*/ + */ single_declaration single_declaration_nospace .or single_declaration_space; single_declaration_space @@ -924,12 +921,12 @@ centroid_qualifier /* - * <type_qualifier> ::= "const" - * | "attribute" // Vertex only. - * | "varying" - * | "uniform" - * | "__fixed_output" - * | "__fixed_input" + * <type_qualifier> ::= "const" + * | "attribute" // Vertex only. + * | "varying" + * | "uniform" + * | "__fixed_output" + * | "__fixed_input" * * note: this is an extension to the standard language specification, * normally slang disallows __fixed_output and __fixed_input type qualifiers @@ -1013,7 +1010,7 @@ type_specifier_nospace /* * <struct_specifier> ::= "struct" <identifier> "{" <struct_declaration_list> "}" - * | "struct" "{" <struct_declaration_list> "}" + * | "struct" "{" <struct_declaration_list> "}" */ struct_specifier "struct" .and struct_specifier_1 .and optional_space .and lbrace .error LBRACE_EXPECTED .and @@ -1025,7 +1022,7 @@ struct_specifier_2 /* * <struct_declaration_list> ::= <struct_declaration> - * | <struct_declaration_list> <struct_declaration> + * | <struct_declaration_list> <struct_declaration> */ struct_declaration_list struct_declaration .and .loop struct_declaration .emit FIELD_NEXT; @@ -1042,7 +1039,7 @@ struct_declaration_nospace /* * <struct_declarator_list> ::= <struct_declarator> - * | <struct_declarator_list> "," <struct_declarator> + * | <struct_declarator_list> "," <struct_declarator> */ struct_declarator_list struct_declarator .and .loop struct_declarator_list_1 .emit FIELD_NEXT; diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c index d23ae4d8cb5..851335d9c58 100644 --- a/src/mesa/shader/slang/slang_codegen.c +++ b/src/mesa/shader/slang/slang_codegen.c @@ -1477,6 +1477,8 @@ _slang_simple_writemask(GLuint writemask, GLuint swizzle) * Convert the given swizzle into a writemask. In some cases this * is trivial, in other cases, we'll need to also swizzle the right * hand side to put components in the right places. + * See comment above for more info. + * XXX this function could be simplified and should probably be renamed. * \param swizzle the incoming swizzle * \param writemaskOut returns the writemask * \param swizzleOut swizzle to apply to the right-hand-side @@ -3114,7 +3116,7 @@ _slang_gen_struct_field(slang_assemble_ctx * A, slang_operation *oper) /* oper->a_id is the field name */ slang_ir_node *base, *n; slang_typeinfo field_ti; - GLint fieldSize, fieldOffset = -1, swz; + GLint fieldSize, fieldOffset = -1; /* type of field */ slang_typeinfo_construct(&field_ti); @@ -3147,22 +3149,12 @@ _slang_gen_struct_field(slang_assemble_ctx * A, slang_operation *oper) if (!n) return NULL; - - /* setup the storage info for this node */ - swz = fieldOffset % 4; - n->Field = (char *) oper->a_id; - n->Store = _slang_new_ir_storage_relative(fieldOffset / 4, - fieldSize, - base->Store); - if (fieldSize == 1) - n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz); - else if (fieldSize == 2) - n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, - SWIZZLE_NIL, SWIZZLE_NIL); - else if (fieldSize == 3) - n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, - SWIZZLE_Z, SWIZZLE_NIL); + + /* Store the field's offset in storage->Index */ + n->Store = _slang_new_ir_storage(base->Store->File, + fieldOffset, + fieldSize); return n; } @@ -3255,12 +3247,12 @@ _slang_gen_array_element(slang_assemble_ctx * A, slang_operation *oper) } elem = new_node2(IR_ELEMENT, array, index); - elem->Store = _slang_new_ir_storage_relative(constIndex, - elemSize, - array->Store); - assert(elem->Store->Parent); - /* XXX try to do some array bounds checking here */ + /* The storage info here will be updated during code emit */ + elem->Store = _slang_new_ir_storage(array->Store->File, + array->Store->Index, + elemSize); + return elem; } else { diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c index 72b83c04224..07c40eaa324 100644 --- a/src/mesa/shader/slang/slang_compile.c +++ b/src/mesa/shader/slang/slang_compile.c @@ -167,6 +167,16 @@ typedef struct slang_output_ctx_ /* _slang_compile() */ + +/* Debugging aid, print file/line where parsing error is detected */ +#define RETURN0 \ + do { \ + if (0) \ + printf("slang error at %s:%d\n", __FILE__, __LINE__); \ + return 0; \ + } while (0) + + static void parse_identifier_str(slang_parse_ctx * C, char **id) { @@ -223,7 +233,7 @@ parse_float(slang_parse_ctx * C, float *number) _mesa_strlen(exponent) + 3) * sizeof(char)); if (whole == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } slang_string_copy(whole, integral); @@ -247,7 +257,7 @@ check_revision(slang_parse_ctx * C) { if (*C->I != REVISION) { slang_info_log_error(C->L, "Internal compiler error."); - return 0; + RETURN0; } C->I++; return 1; @@ -387,23 +397,23 @@ parse_struct_field(slang_parse_ctx * C, slang_output_ctx * O, o.structs = st->structs; if (!parse_type_specifier(C, &o, sp)) - return 0; + RETURN0; do { slang_atom a_name; slang_variable *var = slang_variable_scope_grow(st->fields); if (!var) { slang_info_log_memory(C->L); - return 0; + RETURN0; } a_name = parse_identifier(C); if (_slang_locate_variable(st->fields, a_name, GL_FALSE)) { slang_info_log_error(C->L, "duplicate field '%s'", (char *) a_name); - return 0; + RETURN0; } if (!parse_struct_field_var(C, &o, var, a_name, sp)) - return 0; + RETURN0; } while (*C->I++ != FIELD_NONE); @@ -419,26 +429,26 @@ parse_struct(slang_parse_ctx * C, slang_output_ctx * O, slang_struct ** st) /* parse struct name (if any) and make sure it is unique in current scope */ a_name = parse_identifier(C); if (a_name == SLANG_ATOM_NULL) - return 0; + RETURN0; name = slang_atom_pool_id(C->atoms, a_name); if (name[0] != '\0' && slang_struct_scope_find(O->structs, a_name, 0) != NULL) { slang_info_log_error(C->L, "%s: duplicate type name.", name); - return 0; + RETURN0; } /* set-up a new struct */ *st = (slang_struct *) _slang_alloc(sizeof(slang_struct)); if (*st == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!slang_struct_construct(*st)) { _slang_free(*st); *st = NULL; slang_info_log_memory(C->L); - return 0; + RETURN0; } (**st).a_name = a_name; (**st).structs->outer_scope = O->structs; @@ -450,7 +460,7 @@ parse_struct(slang_parse_ctx * C, slang_output_ctx * O, slang_struct ** st) slang_type_specifier_ctr(&sp); if (!parse_struct_field(C, O, *st, &sp)) { slang_type_specifier_dtr(&sp); - return 0; + RETURN0; } slang_type_specifier_dtr(&sp); } @@ -468,14 +478,14 @@ parse_struct(slang_parse_ctx * C, slang_output_ctx * O, slang_struct ** st) * sizeof(slang_struct)); if (O->structs->structs == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } s = &O->structs->structs[O->structs->num_structs]; if (!slang_struct_construct(s)) - return 0; + RETURN0; O->structs->num_structs++; if (!slang_struct_copy(s, *st)) - return 0; + RETURN0; } return 1; @@ -498,7 +508,7 @@ parse_type_variant(slang_parse_ctx * C, slang_type_variant *variant) *variant = SLANG_INVARIANT; return 1; default: - return 0; + RETURN0; } } @@ -519,7 +529,7 @@ parse_type_centroid(slang_parse_ctx * C, slang_type_centroid *centroid) *centroid = SLANG_CENTROID; return 1; default: - return 0; + RETURN0; } } @@ -560,7 +570,7 @@ parse_type_qualifier(slang_parse_ctx * C, slang_type_qualifier * qual) *qual = SLANG_QUAL_FIXEDINPUT; break; default: - return 0; + RETURN0; } return 1; } @@ -698,7 +708,7 @@ parse_type_specifier(slang_parse_ctx * C, slang_output_ctx * O, case TYPE_SPECIFIER_STRUCT: spec->type = SLANG_SPEC_STRUCT; if (!parse_struct(C, O, &spec->_struct)) - return 0; + RETURN0; break; case TYPE_SPECIFIER_TYPENAME: spec->type = SLANG_SPEC_STRUCT; @@ -708,31 +718,31 @@ parse_type_specifier(slang_parse_ctx * C, slang_output_ctx * O, a_name = parse_identifier(C); if (a_name == NULL) - return 0; + RETURN0; stru = slang_struct_scope_find(O->structs, a_name, 1); if (stru == NULL) { slang_info_log_error(C->L, "undeclared type name '%s'", slang_atom_pool_id(C->atoms, a_name)); - return 0; + RETURN0; } spec->_struct = (slang_struct *) _slang_alloc(sizeof(slang_struct)); if (spec->_struct == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!slang_struct_construct(spec->_struct)) { _slang_free(spec->_struct); spec->_struct = NULL; - return 0; + RETURN0; } if (!slang_struct_copy(spec->_struct, stru)) - return 0; + RETURN0; } break; default: - return 0; + RETURN0; } return 1; } @@ -762,7 +772,7 @@ parse_type_precision(slang_parse_ctx *C, *precision = SLANG_PREC_HIGH; return 1; default: - return 0; + RETURN0; } } @@ -771,36 +781,36 @@ parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O, slang_fully_specified_type * type) { if (!parse_type_variant(C, &type->variant)) - return 0; + RETURN0; if (!parse_type_centroid(C, &type->centroid)) - return 0; + RETURN0; if (!parse_type_qualifier(C, &type->qualifier)) - return 0; + RETURN0; if (!parse_type_precision(C, &type->precision)) - return 0; + RETURN0; if (!parse_type_specifier(C, O, &type->specifier)) - return 0; + RETURN0; if (!O->allow_invariant && type->variant == SLANG_INVARIANT) { slang_info_log_error(C->L, "'invariant' keyword not allowed (perhaps set #version 120)"); - return 0; + RETURN0; } if (!O->allow_centroid && type->centroid == SLANG_CENTROID) { slang_info_log_error(C->L, "'centroid' keyword not allowed (perhaps set #version 120)"); - return 0; + RETURN0; } else if (type->centroid == SLANG_CENTROID && type->qualifier != SLANG_QUAL_VARYING) { slang_info_log_error(C->L, "'centroid' keyword only allowed for varying vars"); - return 0; + RETURN0; } @@ -809,7 +819,7 @@ parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O, type->variant == SLANG_INVARIANT) { slang_info_log_error(C->L, "invariant qualifer only allowed for varying vars"); - return 0; + RETURN0; } */ @@ -824,7 +834,7 @@ parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O, /* only default is allowed */ if (type->precision != SLANG_PREC_DEFAULT) { slang_info_log_error(C->L, "precision qualifiers not allowed"); - return 0; + RETURN0; } } @@ -935,7 +945,7 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; while (*C->I != OP_END) if (!parse_child_operation(C, O, oper, 1)) - return 0; + RETURN0; C->I++; break; case OP_BLOCK_BEGIN_NEW_SCOPE: @@ -947,7 +957,7 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, o.vars = oper->locals; while (*C->I != OP_END) if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; C->I++; } break; @@ -963,7 +973,7 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, * than one declarators */ if (!parse_declaration(C, O)) - return 0; + RETURN0; if (first_var < O->vars->num_variables) { const unsigned int num_vars = O->vars->num_variables - first_var; unsigned int i; @@ -972,7 +982,7 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, oper->children = slang_operation_new(num_vars); if (oper->children == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } for (i = first_var; i < O->vars->num_variables; i++) { slang_operation *o = &oper->children[i - first_var]; @@ -983,7 +993,7 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, if (!legal_identifier(o->a_id)) { slang_info_log_error(C->L, "illegal variable name '%s'", (char *) o->a_id); - return 0; + RETURN0; } } } @@ -996,10 +1006,10 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, oper->type = SLANG_OPER_ASM; oper->a_id = parse_identifier(C); if (oper->a_id == SLANG_ATOM_NULL) - return 0; + RETURN0; while (*C->I != OP_END) { if (!parse_child_operation(C, O, oper, 0)) - return 0; + RETURN0; } C->I++; break; @@ -1015,21 +1025,21 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, case OP_RETURN: oper->type = SLANG_OPER_RETURN; if (!parse_child_operation(C, O, oper, 0)) - return 0; + RETURN0; break; case OP_EXPRESSION: oper->type = SLANG_OPER_EXPRESSION; if (!parse_child_operation(C, O, oper, 0)) - return 0; + RETURN0; break; case OP_IF: oper->type = SLANG_OPER_IF; if (!parse_child_operation(C, O, oper, 0)) - return 0; + RETURN0; if (!parse_child_operation(C, O, oper, 1)) - return 0; + RETURN0; if (!parse_child_operation(C, O, oper, 1)) - return 0; + RETURN0; break; case OP_WHILE: { @@ -1038,17 +1048,17 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, oper->type = SLANG_OPER_WHILE; o.vars = oper->locals; if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; } break; case OP_DO: oper->type = SLANG_OPER_DO; if (!parse_child_operation(C, O, oper, 1)) - return 0; + RETURN0; if (!parse_child_operation(C, O, oper, 0)) - return 0; + RETURN0; break; case OP_FOR: { @@ -1057,13 +1067,13 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, oper->type = SLANG_OPER_FOR; o.vars = oper->locals; if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; if (!parse_child_operation(C, &o, oper, 0)) - return 0; + RETURN0; if (!parse_child_operation(C, &o, oper, 1)) - return 0; + RETURN0; } break; case OP_PRECISION: @@ -1077,7 +1087,7 @@ parse_statement(slang_parse_ctx * C, slang_output_ctx * O, } break; default: - return 0; + RETURN0; } return 1; } @@ -1092,7 +1102,7 @@ handle_nary_expression(slang_parse_ctx * C, slang_operation * op, op->children = slang_operation_new(n); if (op->children == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } op->num_children = n; @@ -1110,7 +1120,7 @@ handle_nary_expression(slang_parse_ctx * C, slang_operation * op, *total_ops * sizeof(slang_operation)); if (*ops == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } return 1; } @@ -1143,12 +1153,12 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, (num_ops + 1) * sizeof(slang_operation)); if (ops == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } op = &ops[num_ops]; if (!slang_operation_construct(op)) { slang_info_log_memory(C->L); - return 0; + RETURN0; } num_ops++; op->locals->outer_scope = O->vars; @@ -1160,7 +1170,7 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, case OP_PUSH_BOOL: op->type = SLANG_OPER_LITERAL_BOOL; if (!parse_number(C, &number)) - return 0; + RETURN0; op->literal[0] = op->literal[1] = op->literal[2] = @@ -1170,7 +1180,7 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, case OP_PUSH_INT: op->type = SLANG_OPER_LITERAL_INT; if (!parse_number(C, &number)) - return 0; + RETURN0; op->literal[0] = op->literal[1] = op->literal[2] = @@ -1180,7 +1190,7 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, case OP_PUSH_FLOAT: op->type = SLANG_OPER_LITERAL_FLOAT; if (!parse_float(C, &op->literal[0])) - return 0; + RETURN0; op->literal[1] = op->literal[2] = op->literal[3] = op->literal[0]; @@ -1190,37 +1200,37 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, op->type = SLANG_OPER_IDENTIFIER; op->a_id = parse_identifier(C); if (op->a_id == SLANG_ATOM_NULL) - return 0; + RETURN0; break; case OP_SEQUENCE: op->type = SLANG_OPER_SEQUENCE; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_ASSIGN: op->type = SLANG_OPER_ASSIGN; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_ADDASSIGN: op->type = SLANG_OPER_ADDASSIGN; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_SUBASSIGN: op->type = SLANG_OPER_SUBASSIGN; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_MULASSIGN: op->type = SLANG_OPER_MULASSIGN; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_DIVASSIGN: op->type = SLANG_OPER_DIVASSIGN; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; /*case OP_MODASSIGN: */ /*case OP_LSHASSIGN: */ @@ -1231,22 +1241,22 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, case OP_SELECT: op->type = SLANG_OPER_SELECT; if (!handle_nary_expression(C, op, &ops, &num_ops, 3)) - return 0; + RETURN0; break; case OP_LOGICALOR: op->type = SLANG_OPER_LOGICALOR; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_LOGICALXOR: op->type = SLANG_OPER_LOGICALXOR; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_LOGICALAND: op->type = SLANG_OPER_LOGICALAND; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; /*case OP_BITOR: */ /*case OP_BITXOR: */ @@ -1254,95 +1264,95 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, case OP_EQUAL: op->type = SLANG_OPER_EQUAL; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_NOTEQUAL: op->type = SLANG_OPER_NOTEQUAL; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_LESS: op->type = SLANG_OPER_LESS; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_GREATER: op->type = SLANG_OPER_GREATER; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_LESSEQUAL: op->type = SLANG_OPER_LESSEQUAL; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_GREATEREQUAL: op->type = SLANG_OPER_GREATEREQUAL; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; /*case OP_LSHIFT: */ /*case OP_RSHIFT: */ case OP_ADD: op->type = SLANG_OPER_ADD; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_SUBTRACT: op->type = SLANG_OPER_SUBTRACT; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_MULTIPLY: op->type = SLANG_OPER_MULTIPLY; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_DIVIDE: op->type = SLANG_OPER_DIVIDE; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; /*case OP_MODULUS: */ case OP_PREINCREMENT: op->type = SLANG_OPER_PREINCREMENT; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_PREDECREMENT: op->type = SLANG_OPER_PREDECREMENT; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_PLUS: op->type = SLANG_OPER_PLUS; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_MINUS: op->type = SLANG_OPER_MINUS; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_NOT: op->type = SLANG_OPER_NOT; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; /*case OP_COMPLEMENT: */ case OP_SUBSCRIPT: op->type = SLANG_OPER_SUBSCRIPT; if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) - return 0; + RETURN0; break; case OP_CALL: op->type = SLANG_OPER_CALL; op->a_id = parse_identifier(C); if (op->a_id == SLANG_ATOM_NULL) - return 0; + RETURN0; while (*C->I != OP_END) if (!parse_child_operation(C, O, op, 0)) - return 0; + RETURN0; C->I++; if (!C->parsing_builtin @@ -1352,7 +1362,7 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, id = slang_atom_pool_id(C->atoms, op->a_id); if (!is_constructor_name(id, op->a_id, O->structs)) { slang_info_log_error(C->L, "%s: undeclared function name.", id); - return 0; + RETURN0; } } break; @@ -1360,22 +1370,22 @@ parse_expression(slang_parse_ctx * C, slang_output_ctx * O, op->type = SLANG_OPER_FIELD; op->a_id = parse_identifier(C); if (op->a_id == SLANG_ATOM_NULL) - return 0; + RETURN0; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_POSTINCREMENT: op->type = SLANG_OPER_POSTINCREMENT; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; case OP_POSTDECREMENT: op->type = SLANG_OPER_POSTDECREMENT; if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) - return 0; + RETURN0; break; default: - return 0; + RETURN0; } } C->I++; @@ -1406,7 +1416,7 @@ parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, * two at most) because not all combinations are valid */ if (!parse_type_qualifier(C, ¶m->type.qualifier)) - return 0; + RETURN0; param_qual = *C->I++; switch (param_qual) { @@ -1414,7 +1424,7 @@ parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, if (param->type.qualifier != SLANG_QUAL_CONST && param->type.qualifier != SLANG_QUAL_NONE) { slang_info_log_error(C->L, "Invalid type qualifier."); - return 0; + RETURN0; } break; case PARAM_QUALIFIER_OUT: @@ -1422,7 +1432,7 @@ parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, param->type.qualifier = SLANG_QUAL_OUT; else { slang_info_log_error(C->L, "Invalid type qualifier."); - return 0; + RETURN0; } break; case PARAM_QUALIFIER_INOUT: @@ -1430,11 +1440,11 @@ parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, param->type.qualifier = SLANG_QUAL_INOUT; else { slang_info_log_error(C->L, "Invalid type qualifier."); - return 0; + RETURN0; } break; default: - return 0; + RETURN0; } /* parse precision qualifier (lowp, mediump, highp */ @@ -1444,10 +1454,10 @@ parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, /* parse parameter's type specifier and name */ if (!parse_type_specifier(C, O, ¶m->type.specifier)) - return 0; + RETURN0; param->a_name = parse_identifier(C); if (param->a_name == SLANG_ATOM_NULL) - return 0; + RETURN0; /* if the parameter is an array, parse its size (the size must be * explicitly defined @@ -1564,13 +1574,13 @@ parse_operator_name(slang_parse_ctx * C) slang_atom_pool_atom(C->atoms, operator_names[i].o_name); if (atom == SLANG_ATOM_NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } C->I++; return atom; } } - return 0; + RETURN0; } @@ -1581,7 +1591,7 @@ parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O, GLuint functype; /* parse function type and name */ if (!parse_fully_specified_type(C, O, &func->header.type)) - return 0; + RETURN0; functype = *C->I++; switch (functype) { @@ -1589,35 +1599,35 @@ parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O, func->kind = SLANG_FUNC_ORDINARY; func->header.a_name = parse_identifier(C); if (func->header.a_name == SLANG_ATOM_NULL) - return 0; + RETURN0; break; case FUNCTION_CONSTRUCTOR: func->kind = SLANG_FUNC_CONSTRUCTOR; if (func->header.type.specifier.type == SLANG_SPEC_STRUCT) - return 0; + RETURN0; func->header.a_name = slang_atom_pool_atom(C->atoms, slang_type_specifier_type_to_string (func->header.type.specifier.type)); if (func->header.a_name == SLANG_ATOM_NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } break; case FUNCTION_OPERATOR: func->kind = SLANG_FUNC_OPERATOR; func->header.a_name = parse_operator_name(C); if (func->header.a_name == SLANG_ATOM_NULL) - return 0; + RETURN0; break; default: - return 0; + RETURN0; } if (!legal_identifier(func->header.a_name)) { slang_info_log_error(C->L, "illegal function name '%s'", (char *) func->header.a_name); - return 0; + RETURN0; } /* parse function parameters */ @@ -1625,10 +1635,10 @@ parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O, slang_variable *p = slang_variable_scope_grow(func->parameters); if (!p) { slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!parse_parameter_declaration(C, O, p)) - return 0; + RETURN0; } /* if the function returns a value, append a hidden __retVal 'out' @@ -1662,19 +1672,19 @@ parse_function_definition(slang_parse_ctx * C, slang_output_ctx * O, slang_output_ctx o = *O; if (!parse_function_prototype(C, O, func)) - return 0; + RETURN0; /* create function's body operation */ func->body = (slang_operation *) _slang_alloc(sizeof(slang_operation)); if (func->body == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!slang_operation_construct(func->body)) { _slang_free(func->body); func->body = NULL; slang_info_log_memory(C->L); - return 0; + RETURN0; } /* to parse the body the parse context is modified in order to @@ -1683,7 +1693,7 @@ parse_function_definition(slang_parse_ctx * C, slang_output_ctx * O, C->global_scope = GL_FALSE; o.vars = func->parameters; if (!parse_statement(C, &o, func->body)) - return 0; + RETURN0; C->global_scope = GL_TRUE; return 1; @@ -1779,46 +1789,46 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, slang_info_log_error(C->L, "declaration of '%s' conflicts with previous declaration", (char *) a_name); - return 0; + RETURN0; } /* make room for the new variable and initialize it */ var = slang_variable_scope_grow(O->vars); if (!var) { slang_info_log_memory(C->L); - return 0; + RETURN0; } /* copy the declarator qualifier type, parse the identifier */ var->type.qualifier = type->qualifier; var->a_name = a_name; if (var->a_name == SLANG_ATOM_NULL) - return 0; + RETURN0; switch (*C->I++) { case VARIABLE_NONE: /* simple variable declarator - just copy the specifier */ if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) - return 0; + RETURN0; break; case VARIABLE_INITIALIZER: /* initialized variable - copy the specifier and parse the expression */ if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) - return 0; + RETURN0; var->initializer = (slang_operation *) _slang_alloc(sizeof(slang_operation)); if (var->initializer == NULL) { slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!slang_operation_construct(var->initializer)) { _slang_free(var->initializer); var->initializer = NULL; slang_info_log_memory(C->L); - return 0; + RETURN0; } if (!parse_expression(C, O, var->initializer)) - return 0; + RETURN0; break; case VARIABLE_ARRAY_UNKNOWN: /* unsized array - mark it as array and copy the specifier to @@ -1834,7 +1844,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, return GL_FALSE; break; default: - return 0; + RETURN0; } /* allocate global address space for a variable with a known size */ @@ -1858,7 +1868,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, A.log = C->L; A.curFuncEndLabel = NULL; if (!_slang_codegen_global_variable(&A, var, C->type)) - return 0; + RETURN0; } /* initialize global variable */ @@ -1871,7 +1881,7 @@ parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, A.space.structs = O->structs; A.space.vars = O->vars; if (!initialize_global(&A, var)) - return 0; + RETURN0; } } return 1; @@ -1888,17 +1898,17 @@ parse_init_declarator_list(slang_parse_ctx * C, slang_output_ctx * O) /* parse the fully specified type, common to all declarators */ if (!slang_fully_specified_type_construct(&type)) - return 0; + RETURN0; if (!parse_fully_specified_type(C, O, &type)) { slang_fully_specified_type_destruct(&type); - return 0; + RETURN0; } /* parse declarators, pass-in the parsed type */ do { if (!parse_init_declarator(C, O, &type)) { slang_fully_specified_type_destruct(&type); - return 0; + RETURN0; } } while (*C->I++ == DECLARATOR_NEXT); @@ -2005,18 +2015,18 @@ parse_declaration(slang_parse_ctx * C, slang_output_ctx * O) switch (*C->I++) { case DECLARATION_INIT_DECLARATOR_LIST: if (!parse_init_declarator_list(C, O)) - return 0; + RETURN0; break; case DECLARATION_FUNCTION_PROTOTYPE: { slang_function *dummy_func; if (!parse_function(C, O, 0, &dummy_func)) - return 0; + RETURN0; } break; default: - return 0; + RETURN0; } return 1; } @@ -2028,7 +2038,7 @@ parse_default_precision(slang_parse_ctx * C, slang_output_ctx * O) if (!O->allow_precision) { slang_info_log_error(C->L, "syntax error at \"precision\""); - return 0; + RETURN0; } precision = *C->I++; @@ -2041,7 +2051,7 @@ parse_default_precision(slang_parse_ctx * C, slang_output_ctx * O) default: _mesa_problem(NULL, "unexpected precision %d at %s:%d\n", precision, __FILE__, __LINE__); - return 0; + RETURN0; } type = *C->I++; @@ -2061,7 +2071,7 @@ parse_default_precision(slang_parse_ctx * C, slang_output_ctx * O) default: _mesa_problem(NULL, "unexpected type %d at %s:%d\n", type, __FILE__, __LINE__); - return 0; + RETURN0; } assert(type < TYPE_SPECIFIER_COUNT); @@ -2108,7 +2118,7 @@ parse_invariant(slang_parse_ctx * C, slang_output_ctx * O) } else { slang_info_log_error(C->L, "syntax error at \"invariant\""); - return 0; + RETURN0; } } diff --git a/src/mesa/shader/slang/slang_emit.c b/src/mesa/shader/slang/slang_emit.c index b67cea7617d..0a3ab39eb10 100644 --- a/src/mesa/shader/slang/slang_emit.c +++ b/src/mesa/shader/slang/slang_emit.c @@ -60,6 +60,8 @@ typedef struct struct gl_program **Subroutines; GLuint NumSubroutines; + GLuint MaxInstructions; /**< size of prog->Instructions[] buffer */ + /* code-gen options */ GLboolean EmitHighLevelInstructions; GLboolean EmitCondCodes; @@ -259,13 +261,16 @@ fix_swizzle(GLuint swizzle) static void storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st) { + const GLboolean relAddr = st->RelAddr; const GLint size = st->Size; GLint index = st->Index; GLuint swizzle = st->Swizzle; + assert(index >= 0); /* if this is storage relative to some parent storage, walk up the tree */ while (st->Parent) { st = st->Parent; + assert(st->Index >= 0); index += st->Index; swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle); } @@ -302,6 +307,8 @@ storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st) } dst->WriteMask = writemask; } + + dst->RelAddr = relAddr; } @@ -316,8 +323,10 @@ storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st) GLuint swizzle = st->Swizzle; /* if this is storage relative to some parent storage, walk up the tree */ + assert(index >= 0); while (st->Parent) { st = st->Parent; + assert(st->Index >= 0); index += st->Index; swizzle = _slang_swizzle_swizzle(fix_swizzle(st->Swizzle), swizzle); } @@ -387,9 +396,17 @@ new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode) _mesa_print_instruction(prog->Instructions + prog->NumInstructions - 1); } #endif - prog->Instructions = _mesa_realloc_instructions(prog->Instructions, - prog->NumInstructions, - prog->NumInstructions + 1); + assert(prog->NumInstructions <= emitInfo->MaxInstructions); + + if (prog->NumInstructions == emitInfo->MaxInstructions) { + /* grow the instruction buffer */ + emitInfo->MaxInstructions += 20; + prog->Instructions = + _mesa_realloc_instructions(prog->Instructions, + prog->NumInstructions, + emitInfo->MaxInstructions); + } + inst = prog->Instructions + prog->NumInstructions; prog->NumInstructions++; _mesa_init_instructions(inst, 1); @@ -403,60 +420,149 @@ new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode) } +static struct prog_instruction * +emit_arl_load(slang_emit_info *emitInfo, + enum register_file file, GLint index, GLuint swizzle) +{ + struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ARL); + inst->SrcReg[0].File = file; + inst->SrcReg[0].Index = index; + inst->SrcReg[0].Swizzle = swizzle; + inst->DstReg.File = PROGRAM_ADDRESS; + inst->DstReg.Index = 0; + inst->DstReg.WriteMask = WRITEMASK_X; + return inst; +} + + /** * Emit a new instruction with given opcode, operands. + * At this point the instruction may have multiple indirect register + * loads/stores. We convert those into ARL loads and address-relative + * operands. See comments inside. + * At some point in the future we could directly emit indirectly addressed + * registers in Mesa GPU instructions. */ static struct prog_instruction * emit_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode, const slang_ir_storage *dst, + const slang_ir_storage *src0, const slang_ir_storage *src1, - const slang_ir_storage *src2, - const slang_ir_storage *src3) + const slang_ir_storage *src2) { - struct gl_program *prog = emitInfo->prog; struct prog_instruction *inst; + GLuint numIndirect = 0; + const slang_ir_storage *src[3]; + slang_ir_storage newSrc[3], newDst; + GLuint i; + GLboolean isTemp[3]; + + isTemp[0] = isTemp[1] = isTemp[2] = GL_FALSE; + + src[0] = src0; + src[1] = src1; + src[2] = src2; + + /* count up how many operands are indirect loads */ + for (i = 0; i < 3; i++) { + if (src[i] && src[i]->IsIndirect) + numIndirect++; + } + if (dst && dst->IsIndirect) + numIndirect++; + + /* Take special steps for indirect register loads. + * If we had multiple address registers this would be simpler. + * For example, this GLSL code: + * x[i] = y[j] + z[k]; + * would translate into something like: + * ARL ADDR.x, i; + * ARL ADDR.y, j; + * ARL ADDR.z, k; + * ADD TEMP[ADDR.x+5], TEMP[ADDR.y+9], TEMP[ADDR.z+4]; + * But since we currently only have one address register we have to do this: + * ARL ADDR.x, i; + * MOV t1, TEMP[ADDR.x+9]; + * ARL ADDR.x, j; + * MOV t2, TEMP[ADDR.x+4]; + * ARL ADDR.x, k; + * ADD TEMP[ADDR.x+5], t1, t2; + * The code here figures this out... + */ + if (numIndirect > 0) { + for (i = 0; i < 3; i++) { + if (src[i] && src[i]->IsIndirect) { + /* load the ARL register with the indirect register */ + emit_arl_load(emitInfo, + src[i]->IndirectFile, + src[i]->IndirectIndex, + src[i]->IndirectSwizzle); + + if (numIndirect > 1) { + /* Need to load src[i] into a temporary register */ + slang_ir_storage srcRelAddr; + alloc_local_temp(emitInfo, &newSrc[i], src[i]->Size); + isTemp[i] = GL_TRUE; + + /* set RelAddr flag on src register */ + srcRelAddr = *src[i]; + srcRelAddr.RelAddr = GL_TRUE; + srcRelAddr.IsIndirect = GL_FALSE; /* not really needed */ + + /* MOV newSrc, srcRelAddr; */ + inst = emit_instruction(emitInfo, + OPCODE_MOV, + &newSrc[i], + &srcRelAddr, + NULL, + NULL); + + src[i] = &newSrc[i]; + } + else { + /* just rewrite the src[i] storage to be ARL-relative */ + newSrc[i] = *src[i]; + newSrc[i].RelAddr = GL_TRUE; + newSrc[i].IsIndirect = GL_FALSE; /* not really needed */ + src[i] = &newSrc[i]; + } + } + } + } - prog->Instructions = _mesa_realloc_instructions(prog->Instructions, - prog->NumInstructions, - prog->NumInstructions + 1); - inst = prog->Instructions + prog->NumInstructions; - prog->NumInstructions++; + /* Take special steps for indirect dest register write */ + if (dst && dst->IsIndirect) { + /* load the ARL register with the indirect register */ + emit_arl_load(emitInfo, + dst->IndirectFile, + dst->IndirectIndex, + dst->IndirectSwizzle); + newDst = *dst; + newDst.RelAddr = GL_TRUE; + newDst.IsIndirect = GL_FALSE; + dst = &newDst; + } - _mesa_init_instructions(inst, 1); - inst->Opcode = opcode; - inst->BranchTarget = -1; /* invalid */ + /* OK, emit the instruction and its dst, src regs */ + inst = new_instruction(emitInfo, opcode); + if (!inst) + return NULL; if (dst) storage_to_dst_reg(&inst->DstReg, dst); - if (src1) - storage_to_src_reg(&inst->SrcReg[0], src1); - if (src2) - storage_to_src_reg(&inst->SrcReg[1], src2); - if (src3) - storage_to_src_reg(&inst->SrcReg[2], src3); - - return inst; -} - + for (i = 0; i < 3; i++) { + if (src[i]) + storage_to_src_reg(&inst->SrcReg[i], src[i]); + } -/** - * Emit an ARL instruction. - */ -static struct prog_instruction * -emit_arl_instruction(slang_emit_info *emitInfo, - GLint addrReg, - const slang_ir_storage *src) -{ - struct prog_instruction *inst; + /* Free any temp registers that we allocated above */ + for (i = 0; i < 3; i++) { + if (isTemp[i]) + _slang_free_temp(emitInfo->vt, &newSrc[i]); + } - assert(addrReg == 0); /* only one addr reg at this time */ - inst = new_instruction(emitInfo, OPCODE_ARL); - storage_to_src_reg(&inst->SrcReg[0], src); - inst->DstReg.File = PROGRAM_ADDRESS; - inst->DstReg.Index = addrReg; - inst->DstReg.WriteMask = WRITEMASK_X; return inst; } @@ -1034,13 +1140,17 @@ emit_fcall(slang_emit_info *emitInfo, slang_ir_node *n) struct gl_program *progSave; struct prog_instruction *inst; GLuint subroutineId; + GLuint maxInstSave; assert(n->Opcode == IR_CALL); assert(n->Label); /* save/push cur program */ + maxInstSave = emitInfo->MaxInstructions; progSave = emitInfo->prog; + emitInfo->prog = new_subroutine(emitInfo, &subroutineId); + emitInfo->MaxInstructions = emitInfo->prog->NumInstructions; _slang_label_set_location(n->Label, emitInfo->prog->NumInstructions, emitInfo->prog); @@ -1072,6 +1182,7 @@ emit_fcall(slang_emit_info *emitInfo, slang_ir_node *n) /* pop/restore cur program */ emitInfo->prog = progSave; + emitInfo->MaxInstructions = maxInstSave; /* emit the function call */ inst = new_instruction(emitInfo, OPCODE_CAL); @@ -1212,7 +1323,8 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n) if (inst && _slang_is_temp(emitInfo->vt, n->Children[1]->Store) && (inst->DstReg.File == n->Children[1]->Store->File) && - (inst->DstReg.Index == n->Children[1]->Store->Index)) { + (inst->DstReg.Index == n->Children[1]->Store->Index) && + !n->Children[0]->Store->IsIndirect) { /* Peephole optimization: * The Right-Hand-Side has its results in a temporary place. * Modify the RHS (and the prev instruction) to store its results @@ -1670,80 +1782,38 @@ emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n) inst = emit(emitInfo, n->Children[0]); - /* setup storage info, if needed */ - if (!n->Store->Parent) - n->Store->Parent = n->Children[0]->Store; - +#if 0 assert(n->Store->Parent); - + /* Apply this node's swizzle to parent's storage */ + GLuint swizzle = n->Store->Swizzle; + _slang_copy_ir_storage(n->Store, n->Store->Parent); + n->Store->Swizzle = _slang_swizzle_swizzle(n->Store->Swizzle, swizzle); + assert(!n->Store->Parent); +#endif return inst; } /** - * Move a block registers from src to dst (or move a single register). - * \param size size of block, in floats (<=4 means one register) + * Dereference array element: element == array[index] + * This basically involves emitting code for computing the array index + * and updating the node/element's storage info. */ static struct prog_instruction * -move_block(slang_emit_info *emitInfo, - GLuint size, GLboolean relAddr, - const slang_ir_storage *dst, - const slang_ir_storage *src) +emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n) { + slang_ir_storage *arrayStore, *indexStore; + const int elemSize = n->Store->Size; /* number of floats */ + const GLint elemSizeVec = (elemSize + 3) / 4; /* number of vec4 */ struct prog_instruction *inst; - if (size > 4) { - /* move matrix/struct etc (block of registers) */ - slang_ir_storage dstStore = *dst; - slang_ir_storage srcStore = *src; - - dstStore.Size = 4; - srcStore.Size = 4; - while (size >= 4) { - inst = emit_instruction(emitInfo, OPCODE_MOV, - &dstStore, - &srcStore, - NULL, - NULL); - inst->SrcReg[0].RelAddr = relAddr; - inst_comment(inst, "IR_COPY block"); - srcStore.Index++; - dstStore.Index++; - size -= 4; - } - } - else { - /* single register move */ - inst = emit_instruction(emitInfo, - OPCODE_MOV, - dst, - src, - NULL, - NULL); - inst->SrcReg[0].RelAddr = relAddr; - } - return inst; -} - - - -/** - * Dereference array element. Just resolve storage for the array - * element represented by this node. - * This is typically where Indirect addressing comes into play. - * See comments on struct slang_ir_storage. - */ -static struct prog_instruction * -emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n) -{ assert(n->Opcode == IR_ELEMENT); - assert(n->Store); - assert(n->Store->File == PROGRAM_UNDEFINED); - assert(n->Store->Parent); - assert(n->Store->Size > 0); + assert(elemSize > 0); + /* special case for built-in state variables, like light state */ { slang_ir_storage *root = n->Store; + assert(!root->Parent); while (root->Parent) root = root->Parent; @@ -1754,69 +1824,98 @@ emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n) } } - /* do codegen for array */ + /* do codegen for array itself */ emit(emitInfo, n->Children[0]); + arrayStore = n->Children[0]->Store; + + /* The initial array element storage is the array's storage, + * then modified below. + */ + _slang_copy_ir_storage(n->Store, arrayStore); + if (n->Children[1]->Opcode == IR_FLOAT) { - /* Constant array index. - * Set Store's index to be the offset of the array element in - * the register file. - */ + /* Constant array index */ const GLint element = (GLint) n->Children[1]->Value[0]; - const GLint sz = (n->Store->Size + 3) / 4; /* size in slots/registers */ - n->Store->Index = sz * element; - assert(n->Store->Parent); + /* this element's storage is the array's storage, plus constant offset */ + n->Store->Index += elemSizeVec * element; } else { /* Variable array index */ - struct prog_instruction *inst; /* do codegen for array index expression */ emit(emitInfo, n->Children[1]); + indexStore = n->Children[1]->Store; + + if (indexStore->IsIndirect) { + /* need to put the array index into a temporary since we can't + * directly support a[b[i]] constructs. + */ + - /* allocate temp storage for the array element */ - assert(n->Store->Index < 0); - n->Store->File = PROGRAM_TEMPORARY; - n->Store->Parent = NULL; - alloc_node_storage(emitInfo, n, -1); + /*indexStore = tempstore();*/ + } - if (n->Store->Size > 4) { - /* need to multiply the index by the element size */ - const GLint elemSize = (n->Store->Size + 3) / 4; - slang_ir_storage indexTemp, elemSizeStore; - /* constant containing the element size */ - constant_to_storage(emitInfo, (float) elemSize, &elemSizeStore); + if (elemSize > 4) { + /* need to multiply array index by array element size */ + struct prog_instruction *inst; + slang_ir_storage *indexTemp; + slang_ir_storage elemSizeStore; /* allocate 1 float indexTemp */ - alloc_local_temp(emitInfo, &indexTemp, 1); + indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); + _slang_alloc_temp(emitInfo->vt, indexTemp); + + /* allocate a constant containing the element size */ + constant_to_storage(emitInfo, (float) elemSizeVec, &elemSizeStore); - /* MUL temp, index, elemSize */ - inst = emit_instruction(emitInfo, OPCODE_MUL, - &indexTemp, /* dest */ - n->Children[1]->Store, /* the index */ + /* multiply array index by element size */ + inst = emit_instruction(emitInfo, + OPCODE_MUL, + indexTemp, /* dest */ + indexStore, /* the index */ &elemSizeStore, NULL); - /* load ADDR[0].X = temp */ - inst = emit_arl_instruction(emitInfo, 0, &indexTemp); - - _slang_free_temp(emitInfo->vt, &indexTemp); + indexStore = indexTemp; } - else { - /* simply load address reg w/ array index */ - inst = emit_arl_instruction(emitInfo, 0, n->Children[1]->Store); + + if (arrayStore->IsIndirect) { + /* ex: in a[i][j], a[i] (the arrayStore) is indirect */ + /* Need to add indexStore to arrayStore->Indirect store */ + slang_ir_storage indirectArray; + slang_ir_storage *indexTemp; + + _slang_init_ir_storage(&indirectArray, + arrayStore->IndirectFile, + arrayStore->IndirectIndex, + 1, + arrayStore->IndirectSwizzle); + + /* allocate 1 float indexTemp */ + indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1); + _slang_alloc_temp(emitInfo->vt, indexTemp); + + inst = emit_instruction(emitInfo, + OPCODE_ADD, + indexTemp, /* dest */ + indexStore, /* the index */ + &indirectArray, /* indirect array base */ + NULL); + + indexStore = indexTemp; } - /* copy from array element to temp storage */ - move_block(emitInfo, n->Store->Size, GL_TRUE, - n->Store, n->Children[0]->Store); + /* update the array element storage info */ + n->Store->IsIndirect = GL_TRUE; + n->Store->IndirectFile = indexStore->File; + n->Store->IndirectIndex = indexStore->Index; + n->Store->IndirectSwizzle = indexStore->Swizzle; } - /* if array element size is one, make sure we only access X */ - if (n->Store->Size == 1) - n->Store->Swizzle = SWIZZLE_XXXX; + n->Store->Size = elemSize; return NULL; /* no instruction */ } @@ -1829,9 +1928,11 @@ static struct prog_instruction * emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n) { slang_ir_storage *root = n->Store; + GLint fieldOffset, fieldSize; assert(n->Opcode == IR_FIELD); + assert(!root->Parent); while (root->Parent) root = root->Parent; @@ -1847,12 +1948,45 @@ emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n) slang_info_log_error(emitInfo->log, "Error parsing state variable"); return NULL; } + return NULL; } else { /* do codegen for struct */ emit(emitInfo, n->Children[0]); + assert(n->Children[0]->Store->Index >= 0); } + fieldOffset = n->Store->Index; + fieldSize = n->Store->Size; + + _slang_copy_ir_storage(n->Store, n->Children[0]->Store); + + n->Store->Index = n->Children[0]->Store->Index + fieldOffset / 4; + /* XXX test this: + n->Store->Index += fieldOffset / 4; + */ + + switch (fieldSize) { + case 1: + { + GLint swz = fieldOffset % 4; + n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz); + } + break; + case 2: + n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, + SWIZZLE_NIL, SWIZZLE_NIL); + break; + case 3: + n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, + SWIZZLE_Z, SWIZZLE_NIL); + break; + default: + n->Store->Swizzle = SWIZZLE_XYZW; + } + + assert(n->Store->Index >= 0); + return NULL; /* no instruction */ } @@ -1909,7 +2043,7 @@ emit_var_decl(slang_emit_info *emitInfo, slang_ir_node *n) /** * Emit code for a reference to a variable. - * Actually, no code is generated but we may do some memory alloation. + * Actually, no code is generated but we may do some memory allocation. * In particular, state vars (uniforms) are allocated on an as-needed basis. */ static struct prog_instruction * @@ -2130,7 +2264,7 @@ _slang_resolve_subroutines(slang_emit_info *emitInfo) total += emitInfo->Subroutines[i]->NumInstructions; } - /* adjust BrancTargets within the functions */ + /* adjust BranchTargets within the functions */ for (i = 0; i < emitInfo->NumSubroutines; i++) { struct gl_program *sub = emitInfo->Subroutines[i]; GLuint j; @@ -2199,6 +2333,7 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt, emitInfo.prog = prog; emitInfo.Subroutines = NULL; emitInfo.NumSubroutines = 0; + emitInfo.MaxInstructions = prog->NumInstructions; emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions; emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes; diff --git a/src/mesa/shader/slang/slang_ir.c b/src/mesa/shader/slang/slang_ir.c index 4fe3a2b85d5..c33c80da999 100644 --- a/src/mesa/shader/slang/slang_ir.c +++ b/src/mesa/shader/slang/slang_ir.c @@ -116,6 +116,20 @@ _slang_ir_info(slang_ir_opcode opcode) } +void +_slang_init_ir_storage(slang_ir_storage *st, + enum register_file file, GLint index, GLint size, + GLuint swizzle) +{ + st->File = file; + st->Index = index; + st->Size = size; + st->Swizzle = swizzle; + st->Parent = NULL; + st->IsIndirect = GL_FALSE; +} + + /** * Return a new slang_ir_storage object. */ @@ -130,6 +144,7 @@ _slang_new_ir_storage(enum register_file file, GLint index, GLint size) st->Size = size; st->Swizzle = SWIZZLE_NOOP; st->Parent = NULL; + st->IsIndirect = GL_FALSE; } return st; } @@ -150,6 +165,7 @@ _slang_new_ir_storage_swz(enum register_file file, GLint index, GLint size, st->Size = size; st->Swizzle = swizzle; st->Parent = NULL; + st->IsIndirect = GL_FALSE; } return st; } @@ -170,11 +186,45 @@ _slang_new_ir_storage_relative(GLint index, GLint size, st->Size = size; st->Swizzle = SWIZZLE_NOOP; st->Parent = parent; + st->IsIndirect = GL_FALSE; + } + return st; +} + + +slang_ir_storage * +_slang_new_ir_storage_indirect(enum register_file file, + GLint index, + GLint size, + enum register_file indirectFile, + GLint indirectIndex, + GLuint indirectSwizzle) +{ + slang_ir_storage *st; + st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage)); + if (st) { + st->File = file; + st->Index = index; + st->Size = size; + st->Swizzle = SWIZZLE_NOOP; + st->IsIndirect = GL_TRUE; + st->IndirectFile = indirectFile; + st->IndirectIndex = indirectIndex; + st->IndirectSwizzle = indirectSwizzle; } return st; } +/* XXX temporary function */ +void +_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src) +{ + *dst = *src; + dst->Parent = NULL; +} + + static const char * _slang_ir_name(slang_ir_opcode opcode) diff --git a/src/mesa/shader/slang/slang_ir.h b/src/mesa/shader/slang/slang_ir.h index a4552ae1442..a258e92e06f 100644 --- a/src/mesa/shader/slang/slang_ir.h +++ b/src/mesa/shader/slang/slang_ir.h @@ -140,24 +140,53 @@ typedef enum /** - * Describes where data storage is allocated. + * Describes where data/variables are stored in the various register files. + * + * In the simple case, the File, Index and Size fields indicate where + * a variable is stored. For example, a vec3 variable may be stored + * as (File=PROGRAM_TEMPORARY, Index=6, Size=3). Or, File[Index]. + * Or, a program input like color may be stored as + * (File=PROGRAM_INPUT,Index=3,Size=4); + * + * For single-float values, the Swizzle field indicates which component + * of the vector contains the float. + * + * If IsIndirect is set, the storage is accessed through an indirect + * register lookup. The value in question will be located at: + * File[Index + IndirectFile[IndirectIndex]] + * + * This is primary used for indexing arrays. For example, consider this + * GLSL code: + * uniform int i; + * float a[10]; + * float x = a[i]; + * + * here, storage for a[i] would be described by (File=PROGRAM_TEMPORAY, + * Index=aPos, IndirectFile=PROGRAM_UNIFORM, IndirectIndex=iPos), which + * would mean TEMP[aPos + UNIFORM[iPos]] */ -struct _slang_ir_storage +struct slang_ir_storage_ { enum register_file File; /**< PROGRAM_TEMPORARY, PROGRAM_INPUT, etc */ GLint Index; /**< -1 means unallocated */ GLint Size; /**< number of floats */ - GLuint Swizzle; + GLuint Swizzle; /**< Swizzle AND writemask info */ GLint RefCount; /**< Used during IR tree delete */ - GLboolean RelAddr; + + GLboolean RelAddr; /* we'll remove this eventually */ + + GLboolean IsIndirect; + enum register_file IndirectFile; + GLint IndirectIndex; + GLuint IndirectSwizzle; /** If Parent is non-null, Index is relative to parent. * The other fields are ignored. */ - struct _slang_ir_storage *Parent; + struct slang_ir_storage_ *Parent; }; -typedef struct _slang_ir_storage slang_ir_storage; +typedef struct slang_ir_storage_ slang_ir_storage; /** @@ -199,6 +228,11 @@ extern const slang_ir_info * _slang_ir_info(slang_ir_opcode opcode); +extern void +_slang_init_ir_storage(slang_ir_storage *st, + enum register_file file, GLint index, GLint size, + GLuint swizzle); + extern slang_ir_storage * _slang_new_ir_storage(enum register_file file, GLint index, GLint size); @@ -212,6 +246,17 @@ _slang_new_ir_storage_relative(GLint index, GLint size, slang_ir_storage *parent); +extern slang_ir_storage * +_slang_new_ir_storage_indirect(enum register_file file, + GLint index, + GLint size, + enum register_file indirectFile, + GLint indirectIndex, + GLuint indirectSwizzle); + +extern void +_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src); + extern void _slang_free_ir_tree(slang_ir_node *n); diff --git a/src/mesa/shader/slang/slang_vartable.h b/src/mesa/shader/slang/slang_vartable.h index 8a3b992c969..94bcd63f45a 100644 --- a/src/mesa/shader/slang/slang_vartable.h +++ b/src/mesa/shader/slang/slang_vartable.h @@ -2,7 +2,7 @@ #ifndef SLANG_VARTABLE_H #define SLANG_VARTABLE_H -struct _slang_ir_storage; +struct slang_ir_storage_; typedef struct slang_var_table_ slang_var_table; @@ -27,16 +27,16 @@ extern struct slang_variable_ * _slang_find_variable(const slang_var_table *t, slang_atom name); extern GLboolean -_slang_alloc_var(slang_var_table *t, struct _slang_ir_storage *store); +_slang_alloc_var(slang_var_table *t, struct slang_ir_storage_ *store); extern GLboolean -_slang_alloc_temp(slang_var_table *t, struct _slang_ir_storage *store); +_slang_alloc_temp(slang_var_table *t, struct slang_ir_storage_ *store); extern void -_slang_free_temp(slang_var_table *t, struct _slang_ir_storage *store); +_slang_free_temp(slang_var_table *t, struct slang_ir_storage_ *store); extern GLboolean -_slang_is_temp(const slang_var_table *t, const struct _slang_ir_storage *store); +_slang_is_temp(const slang_var_table *t, const struct slang_ir_storage_ *store); #endif /* SLANG_VARTABLE_H */ |