void slang_variable_destruct (slang_variable *var) { slang_fully_specified_type_destruct (&var->type); if (var->initializer != NULL) { slang_operation_destruct (var->initializer); slang_alloc_free (var->initializer); } }
void slang_function_destruct (slang_function *func) { slang_variable_destruct (&func->header); slang_variable_scope_destruct (func->parameters); slang_alloc_free (func->parameters); if (func->body != NULL) { slang_operation_destruct (func->body); slang_alloc_free (func->body); } slang_fixup_table_free (&func->fixups); }
void slang_variable_destruct(slang_variable * var) { slang_fully_specified_type_destruct(&var->type); if (var->initializer != NULL) { slang_operation_destruct(var->initializer); _slang_free(var->initializer); } #if 0 if (var->aux) { free(var->aux); } #endif }
static GLboolean assemble_function_call_name_dummyint (slang_assemble_ctx *A, const char *name, slang_operation *params) { slang_operation p[2]; GLboolean result; p[0] = params[0]; if (!slang_operation_construct (&p[1])) return GL_FALSE; p[1].type = slang_oper_literal_int; result = _slang_assemble_function_call_name (A, name, p, 2, GL_FALSE); slang_operation_destruct (&p[1]); return result; }
/** * 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_name_space * space, slang_atom_pool * atoms) { GLboolean isFloat[4]; GLboolean isBool[4]; GLuint i, n; if (oper->type == SLANG_OPER_IDENTIFIER) { /* see if it's a named constant */ GLint value = _slang_lookup_constant((char *) oper->a_id); if (value >= 0) { oper->literal[0] = oper->literal[1] = oper->literal[2] = oper->literal[3] = value; oper->type = SLANG_OPER_LITERAL_INT; return; } } /* 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 (oper->num_children == 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]; } oper->literal_size = oper->children[0].literal_size; slang_operation_destruct(oper); oper->type = SLANG_OPER_LITERAL_FLOAT; return; case SLANG_OPER_SUBTRACT: for (i = 0; i < 4; i++) { oper->literal[i] = oper->children[0].literal[i] - oper->children[1].literal[i]; } oper->literal_size = oper->children[0].literal_size; slang_operation_destruct(oper); oper->type = SLANG_OPER_LITERAL_FLOAT; return; case SLANG_OPER_MULTIPLY: for (i = 0; i < 4; i++) { oper->literal[i] = oper->children[0].literal[i] * oper->children[1].literal[i]; } oper->literal_size = oper->children[0].literal_size; slang_operation_destruct(oper); oper->type = SLANG_OPER_LITERAL_FLOAT; return; case SLANG_OPER_DIVIDE: for (i = 0; i < 4; i++) { oper->literal[i] = oper->children[0].literal[i] / oper->children[1].literal[i]; } oper->literal_size = oper->children[0].literal_size; slang_operation_destruct(oper); oper->type = SLANG_OPER_LITERAL_FLOAT; return; default: ; /* nothing */ } } if (oper->num_children == 1 && isFloat[0]) { switch (oper->type) { case SLANG_OPER_MINUS: for (i = 0; i < 4; i++) { oper->literal[i] = -oper->children[0].literal[i]; } oper->literal_size = oper->children[0].literal_size; slang_operation_destruct(oper); oper->type = SLANG_OPER_LITERAL_FLOAT; return; case SLANG_OPER_PLUS: COPY_4V(oper->literal, oper->children[0].literal); oper->literal_size = oper->children[0].literal_size; slang_operation_destruct(oper); oper->type = SLANG_OPER_LITERAL_FLOAT; return; default: ; /* nothing */ } } if (oper->num_children == 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); } oper->literal_size = oper->children[0].literal_size; slang_operation_destruct(oper); oper->type = SLANG_OPER_LITERAL_BOOL; return; 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); } oper->literal_size = oper->children[0].literal_size; slang_operation_destruct(oper); oper->type = SLANG_OPER_LITERAL_BOOL; return; 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); } oper->literal_size = oper->children[0].literal_size; slang_operation_destruct(oper); oper->type = SLANG_OPER_LITERAL_BOOL; return; default: ; /* nothing */ } } if (oper->num_children == 4 && isFloat[0] && isFloat[1] && isFloat[2] && isFloat[3]) { /* vec4(flt, flt, flt, flt) constructor */ 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]; oper->literal_size = 4; slang_operation_destruct(oper); oper->type = SLANG_OPER_LITERAL_FLOAT; return; } } } if (oper->num_children == 3 && isFloat[0] && isFloat[1] && isFloat[2]) { /* vec3(flt, flt, flt) constructor */ if (oper->type == SLANG_OPER_CALL) { if (strcmp((char *) oper->a_id, "vec3") == 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->literal[2]; oper->literal_size = 3; slang_operation_destruct(oper); oper->type = SLANG_OPER_LITERAL_FLOAT; return; } } } if (oper->num_children == 2 && isFloat[0] && isFloat[1]) { /* vec2(flt, flt) constructor */ if (oper->type == SLANG_OPER_CALL) { if (strcmp((char *) oper->a_id, "vec2") == 0) { oper->literal[0] = oper->children[0].literal[0]; oper->literal[1] = oper->children[1].literal[0]; oper->literal[2] = oper->literal[1]; oper->literal[3] = oper->literal[1]; oper->literal_size = 2; slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */ oper->type = SLANG_OPER_LITERAL_FLOAT; assert(oper->num_children == 0); return; } } } if (oper->num_children == 1 && isFloat[0]) { /* vec2/3/4(flt, flt) constructor */ if (oper->type == SLANG_OPER_CALL) { const char *func = (const char *) oper->a_id; if (strncmp(func, "vec", 3) == 0 && func[3] >= '2' && func[3] <= '4') { oper->literal[0] = oper->literal[1] = oper->literal[2] = oper->literal[3] = oper->children[0].literal[0]; oper->literal_size = func[3] - '0'; assert(oper->literal_size >= 2); assert(oper->literal_size <= 4); slang_operation_destruct(oper); /* XXX oper->locals goes NULL! */ oper->type = SLANG_OPER_LITERAL_FLOAT; assert(oper->num_children == 0); return; } } } }
GLboolean _slang_assemble_operation (slang_assemble_ctx *A, slang_operation *op, slang_ref_type ref) { /* set default results */ A->ref = /*(ref == slang_ref_freelance) ? slang_ref_force : */ref; A->swz.num_components = 0; switch (op->type) { case slang_oper_block_no_new_scope: case slang_oper_block_new_scope: { 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_cleanup_stack (A, &op->children[i])) return GL_FALSE; } } break; case slang_oper_variable_decl: { GLuint i; slang_operation assign; GLboolean result; /* Construct assignment expression placeholder. */ if (!slang_operation_construct (&assign)) return GL_FALSE; assign.type = slang_oper_assign; assign.children = (slang_operation *) slang_alloc_malloc (2 * sizeof (slang_operation)); if (assign.children == NULL) { slang_operation_destruct (&assign); return GL_FALSE; } for (assign.num_children = 0; assign.num_children < 2; assign.num_children++) if (!slang_operation_construct (&assign.children[assign.num_children])) { slang_operation_destruct (&assign); return GL_FALSE; } result = GL_TRUE; for (i = 0; i < op->num_children; i++) { slang_variable *var; var = _slang_locate_variable (op->children[i].locals, op->children[i].a_id, GL_TRUE); if (var == NULL) { result = GL_FALSE; break; } if (var->initializer == NULL) continue; if (!slang_operation_copy (&assign.children[0], &op->children[i]) || !slang_operation_copy (&assign.children[1], var->initializer) || !_slang_assemble_assign (A, &assign, "=", slang_ref_forbid) || !_slang_cleanup_stack (A, &assign)) { result = GL_FALSE; break; } } slang_operation_destruct (&assign); if (!result) return GL_FALSE; } break; case slang_oper_asm: { GLuint i; if (!_slang_assemble_operation (A, &op->children[0], slang_ref_force)) return GL_FALSE; for (i = 1; i < op->num_children; i++) if (!_slang_assemble_operation (A, &op->children[i], slang_ref_forbid)) return GL_FALSE; if (!call_asm_instruction (A, op->a_id)) return GL_FALSE; } break; case slang_oper_break: if (!PLAB (A->file, slang_asm_jump, A->flow.loop_end)) return GL_FALSE; break; case slang_oper_continue: if (!PLAB (A->file, slang_asm_jump, A->flow.loop_start)) return GL_FALSE; break; case slang_oper_discard: if (!PUSH (A->file, slang_asm_discard)) return GL_FALSE; if (!PUSH (A->file, slang_asm_exit)) return GL_FALSE; 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; 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; if (!PLAB (A->file, slang_asm_local_free, 4)) return GL_FALSE; } if (!PLAB (A->file, slang_asm_jump, A->flow.function_end)) return GL_FALSE; break; case slang_oper_expression: if (ref == slang_ref_force) return GL_FALSE; if (!_slang_assemble_operation (A, &op->children[0], ref)) return GL_FALSE; break; case slang_oper_if: if (!_slang_assemble_if (A, op)) return GL_FALSE; break; case slang_oper_while: if (!_slang_assemble_while (A, op)) return GL_FALSE; break; case slang_oper_do: if (!_slang_assemble_do (A, op)) return GL_FALSE; break; case slang_oper_for: if (!_slang_assemble_for (A, op)) return GL_FALSE; 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; 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; 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; A->ref = slang_ref_forbid; break; case slang_oper_identifier: { slang_variable *var; GLuint size; /* find the variable and calculate its size */ var = _slang_locate_variable (op->locals, op->a_id, GL_TRUE); if (var == NULL) return GL_FALSE; size = 0; if (!sizeof_variable (A, &var->type.specifier, slang_qual_none, var->array_len, &size)) return GL_FALSE; /* 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; /* push the variable's address */ if (var->global) { if (!PLAB (A->file, slang_asm_global_addr, var->address)) return GL_FALSE; } else { if (!PLAB2 (A->file, slang_asm_local_addr, var->address, size)) return GL_FALSE; } /* perform the dereference */ if (ref == slang_ref_forbid) { if (!PUSH (A->file, slang_asm_addr_copy)) return GL_FALSE; if (!PLAB (A->file, slang_asm_local_free, 4)) return GL_FALSE; if (!_slang_dereference (A, op)) return GL_FALSE; } } break; case slang_oper_sequence: if (ref == slang_ref_force) return GL_FALSE; if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid/*slang_ref_freelance*/)) return GL_FALSE; if (!_slang_cleanup_stack (A, &op->children[0])) return GL_FALSE; if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid)) return GL_FALSE; A->ref = slang_ref_forbid; break; case slang_oper_assign: if (!_slang_assemble_assign (A, op, "=", ref)) return GL_FALSE; break; case slang_oper_addassign: if (!_slang_assemble_assign (A, op, "+=", ref)) return GL_FALSE; A->ref = ref; break; case slang_oper_subassign: if (!_slang_assemble_assign (A, op, "-=", ref)) return GL_FALSE; A->ref = ref; break; case slang_oper_mulassign: if (!_slang_assemble_assign (A, op, "*=", ref)) return GL_FALSE; A->ref = ref; break; /*case slang_oper_modassign:*/ /*case slang_oper_lshassign:*/ /*case slang_oper_rshassign:*/ /*case slang_oper_orassign:*/ /*case slang_oper_xorassign:*/ /*case slang_oper_andassign:*/ case slang_oper_divassign: if (!_slang_assemble_assign (A, op, "/=", ref)) return GL_FALSE; A->ref = ref; break; case slang_oper_select: if (!_slang_assemble_select (A, op)) return GL_FALSE; A->ref = slang_ref_forbid; break; case slang_oper_logicalor: if (!_slang_assemble_logicalor (A, op)) return GL_FALSE; A->ref = slang_ref_forbid; break; case slang_oper_logicaland: if (!_slang_assemble_logicaland (A, op)) return GL_FALSE; 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; A->ref = slang_ref_forbid; break; /*case slang_oper_bitor:*/ /*case slang_oper_bitxor:*/ /*case slang_oper_bitand:*/ case slang_oper_less: if (!_slang_assemble_function_call_name (A, "<", op->children, 2, GL_FALSE)) return GL_FALSE; 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; 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; 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; 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; 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; 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; 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; A->ref = slang_ref_forbid; break; case slang_oper_equal: if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid)) return GL_FALSE; if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid)) return GL_FALSE; if (!equality (A, op->children, GL_TRUE)) return GL_FALSE; A->ref = slang_ref_forbid; break; case slang_oper_notequal: if (!_slang_assemble_operation (A, &op->children[0], slang_ref_forbid)) return GL_FALSE; if (!_slang_assemble_operation (A, &op->children[1], slang_ref_forbid)) return GL_FALSE; if (!equality (A, op->children, GL_FALSE)) return GL_FALSE; A->ref = slang_ref_forbid; break; case slang_oper_preincrement: if (!_slang_assemble_assign (A, op, "++", ref)) return GL_FALSE; A->ref = ref; break; case slang_oper_predecrement: if (!_slang_assemble_assign (A, op, "--", ref)) return GL_FALSE; A->ref = ref; break; case slang_oper_plus: if (!_slang_dereference (A, op)) return GL_FALSE; 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; 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; A->ref = slang_ref_forbid; break; case slang_oper_subscript: { slang_assembly_typeinfo ti_arr, ti_elem; if (!slang_assembly_typeinfo_construct (&ti_arr)) return GL_FALSE; if (!slang_assembly_typeinfo_construct (&ti_elem)) { slang_assembly_typeinfo_destruct (&ti_arr); return GL_FALSE; } 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; } slang_assembly_typeinfo_destruct (&ti_arr); slang_assembly_typeinfo_destruct (&ti_elem); } 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); if (fun == NULL) { if (!_slang_assemble_constructor (A, op)) return GL_FALSE; } else { if (!_slang_assemble_function_call (A, fun, op->children, op->num_children, GL_FALSE)) return GL_FALSE; } A->ref = slang_ref_forbid; } break; case slang_oper_field: { slang_assembly_typeinfo ti_after, ti_before; if (!slang_assembly_typeinfo_construct (&ti_after)) return GL_FALSE; if (!slang_assembly_typeinfo_construct (&ti_before)) { slang_assembly_typeinfo_destruct (&ti_after); return GL_FALSE; } 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; } slang_assembly_typeinfo_destruct (&ti_after); slang_assembly_typeinfo_destruct (&ti_before); } break; case slang_oper_postincrement: if (!assemble_function_call_name_dummyint (A, "++", op->children)) return GL_FALSE; A->ref = slang_ref_forbid; break; case slang_oper_postdecrement: if (!assemble_function_call_name_dummyint (A, "--", op->children)) return GL_FALSE; A->ref = slang_ref_forbid; break; default: return GL_FALSE; } return GL_TRUE; }