void assert_no_locals(name const & n, expr const & e) { if (!has_local(e)) return; collected_locals ls; collect_locals(e, ls); lean_trace(name({"debug", "inductive_compiler"}), tout() << "\n\nerror: found locals in '" << n << "'\n" << e << "\n"; for (expr const & l : ls.get_collected()) { tout() << mlocal_name(l) << "." << mlocal_pp_name(l) << " : " << mlocal_type(l) << "\n"; });
static GLboolean collect_locals (slang_assemble_ctx *A, slang_operation *op, GLuint *size) { GLuint i; if (!sizeof_variables (A, op->locals, 0, op->locals->num_variables, size)) return GL_FALSE; for (i = 0; i < op->num_children; i++) if (!collect_locals (A, &op->children[i], size)) return GL_FALSE; return GL_TRUE; }
expr extract(expr const & e) { lean_assert(is_nested_declaration(e)); expr const & d = visit(get_nested_declaration_arg(e)); name new_name = mk_name_for(e); name new_real_name = get_namespace(m_env) + new_name; collected_locals locals; collect_locals(d, locals); buffer<name> uparams; collect_univ_params(d).to_buffer(uparams); expr new_value = Fun(locals.get_collected(), d); expr new_type = m_tc.infer(new_value).first; level_param_names new_ps = to_list(uparams); levels ls = param_names_to_levels(new_ps); m_env = module::add(m_env, check(m_env, mk_definition(m_env, new_real_name, new_ps, new_type, new_value))); if (new_name != new_real_name) m_env = add_expr_alias_rec(m_env, new_name, new_real_name); decl_attributes const & attrs = get_nested_declaration_attributes(e); m_env = attrs.apply(m_env, m_ios, new_real_name, get_namespace(m_env)); return mk_app(mk_constant(new_real_name, ls), locals.get_collected()); }
/** \brief Return true iff locals(e1) is a subset of locals(e2) */ bool locals_subset(expr const & e1, expr const & e2) { if (!has_local(e1)) { // empty set is a subset of anything return true; } if (!has_local(e2)) { lean_assert(has_local(e1)); return false; } collected_locals S; collect_locals(e2, S); bool is_sub = true; for_each(e1, [&](expr const & e, unsigned) { if (!is_sub || !has_local(e)) return false; // stop search if (is_local(e) && !S.contains(e)) is_sub = false; return true; }); return is_sub; }
GLboolean _slang_assemble_function (slang_assemble_ctx *A, slang_function *fun) { GLuint param_size, local_size; GLuint skip, cleanup; fun->address = A->file->count; if (fun->body == NULL) { /* jump to the actual function body - we do not know it, so add the instruction * to fixup table */ fun->fixups.table = (GLuint *) slang_alloc_realloc (fun->fixups.table, fun->fixups.count * sizeof (GLuint), (fun->fixups.count + 1) * sizeof (GLuint)); if (fun->fixups.table == NULL) return GL_FALSE; fun->fixups.table[fun->fixups.count] = fun->address; fun->fixups.count++; if (!PUSH (A->file, slang_asm_jump)) return GL_FALSE; return GL_TRUE; } else { GLuint i; /* resolve all fixup table entries and delete it */ for (i = 0; i < fun->fixups.count; i++) A->file->code[fun->fixups.table[i]].param[0] = fun->address; slang_fixup_table_free (&fun->fixups); } /* At this point traverse function formal parameters and code to calculate * total memory size to be allocated on the stack. * During this process the variables will be assigned local addresses to * reference them in the code. * No storage optimizations are performed so exclusive scopes are not detected and shared. */ /* 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; 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; /* calculate local variables size - take into account the four-byte return address and * temporaries for various tasks (4 for addr and 16 for swizzle temporaries). * these include variables from the formal parameter scope and from the code */ 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 (!collect_locals (A, fun->body, &local_size)) return GL_FALSE; /* allocate local variable storage */ if (!PLAB (A->file, slang_asm_local_alloc, local_size - param_size - 4)) return GL_FALSE; /* mark a new frame for function variable storage */ if (!PLAB (A->file, slang_asm_enter, local_size)) return GL_FALSE; /* jump directly to the actual code */ skip = A->file->count; if (!push_new (A->file)) return GL_FALSE; 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; 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; /* 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; /* free local variable storage */ if (!PLAB (A->file, slang_asm_local_free, local_size - param_size - 4)) return GL_FALSE; /* return from the function */ if (!PUSH (A->file, slang_asm_return)) return GL_FALSE; return GL_TRUE; }