diff options
author | George Marques <george@gmarqu.es> | 2021-04-14 14:35:51 -0300 |
---|---|---|
committer | George Marques <george@gmarqu.es> | 2021-04-14 14:35:51 -0300 |
commit | 40502a1689007f3a5995b39b30fa8987463767a4 (patch) | |
tree | a35a9178eeaf80094aeba217f56644e6ccfd9f78 | |
parent | b4b7c97d3839170180e4f3f7c2bd3179b374057a (diff) |
GDScript: Pool temporary values by type on the stack
So the stack slots perform less type changes, which is useful for
future optimizations.
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.cpp | 102 | ||||
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.h | 54 | ||||
-rw-r--r-- | modules/gdscript/gdscript_codegen.h | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 4 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.h | 2 |
5 files changed, 115 insertions, 49 deletions
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index b553dcede3..0aa35e10e7 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -47,7 +47,8 @@ uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool } uint32_t GDScriptByteCodeGenerator::add_local(const StringName &p_name, const GDScriptDataType &p_type) { - int stack_pos = increase_stack(); + int stack_pos = locals.size() + RESERVED_STACK; + locals.push_back(StackSlot(p_type.builtin_type)); add_stack_identifier(p_name, stack_pos); return stack_pos; } @@ -66,25 +67,80 @@ uint32_t GDScriptByteCodeGenerator::add_or_get_name(const StringName &p_name) { return get_name_map_pos(p_name); } -uint32_t GDScriptByteCodeGenerator::add_temporary() { - current_temporaries++; - int idx = increase_stack(); -#ifdef DEBUG_ENABLED - temp_stack.push_back(idx); -#endif - return idx; +uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type) { + Variant::Type temp_type = Variant::NIL; + if (p_type.has_type) { + if (p_type.kind == GDScriptDataType::BUILTIN) { + switch (p_type.builtin_type) { + case Variant::NIL: + case Variant::BOOL: + case Variant::INT: + case Variant::FLOAT: + case Variant::STRING: + case Variant::VECTOR2: + case Variant::VECTOR2I: + case Variant::RECT2: + case Variant::RECT2I: + case Variant::VECTOR3: + case Variant::VECTOR3I: + case Variant::TRANSFORM2D: + case Variant::PLANE: + case Variant::QUAT: + case Variant::AABB: + case Variant::BASIS: + case Variant::TRANSFORM: + case Variant::COLOR: + case Variant::STRING_NAME: + case Variant::NODE_PATH: + case Variant::RID: + case Variant::OBJECT: + case Variant::CALLABLE: + case Variant::SIGNAL: + case Variant::DICTIONARY: + case Variant::ARRAY: + temp_type = p_type.builtin_type; + break; + case Variant::PACKED_BYTE_ARRAY: + case Variant::PACKED_INT32_ARRAY: + case Variant::PACKED_INT64_ARRAY: + case Variant::PACKED_FLOAT32_ARRAY: + case Variant::PACKED_FLOAT64_ARRAY: + case Variant::PACKED_STRING_ARRAY: + case Variant::PACKED_VECTOR2_ARRAY: + case Variant::PACKED_VECTOR3_ARRAY: + case Variant::PACKED_COLOR_ARRAY: + case Variant::VARIANT_MAX: + // Packed arrays are reference counted, so we don't use the pool for them. + temp_type = Variant::NIL; + break; + } + } else { + temp_type = Variant::OBJECT; + } + } + + if (!temporaries_pool.has(temp_type)) { + temporaries_pool[temp_type] = List<int>(); + } + + List<int> &pool = temporaries_pool[temp_type]; + if (pool.is_empty()) { + StackSlot new_temp(temp_type); + pool.push_back(temporaries.size()); + temporaries.push_back(new_temp); + } + int slot = pool.front()->get(); + pool.pop_front(); + used_temporaries.push_back(slot); + return slot; } void GDScriptByteCodeGenerator::pop_temporary() { - ERR_FAIL_COND(current_temporaries == 0); - current_stack_size--; -#ifdef DEBUG_ENABLED - if (temp_stack.back()->get() != current_stack_size) { - ERR_PRINT("Mismatched popping of temporary value"); - } - temp_stack.pop_back(); -#endif - current_temporaries--; + ERR_FAIL_COND(used_temporaries.is_empty()); + int slot_idx = used_temporaries.back()->get(); + const StackSlot &slot = temporaries[slot_idx]; + temporaries_pool[slot.type].push_back(slot_idx); + used_temporaries.pop_back(); } void GDScriptByteCodeGenerator::start_parameters() { @@ -119,12 +175,18 @@ void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName GDScriptFunction *GDScriptByteCodeGenerator::write_end() { #ifdef DEBUG_ENABLED - if (current_temporaries != 0) { - ERR_PRINT("Non-zero temporary variables at end of function: " + itos(current_temporaries)); + if (!used_temporaries.is_empty()) { + ERR_PRINT("Non-zero temporary variables at end of function: " + itos(used_temporaries.size())); } #endif append(GDScriptFunction::OPCODE_END, 0); + for (int i = 0; i < temporaries.size(); i++) { + for (int j = 0; j < temporaries[i].bytecode_indices.size(); j++) { + opcodes.write[temporaries[i].bytecode_indices[j]] = (i + max_locals + RESERVED_STACK) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); + } + } + if (constant_map.size()) { function->_constant_count = constant_map.size(); function->constants.resize(constant_map.size()); @@ -317,7 +379,7 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() { if (debug_stack) { function->stack_debug = stack_debug; } - function->_stack_size = stack_max; + function->_stack_size = RESERVED_STACK + max_locals + temporaries.size(); function->_instruction_args_size = instr_args_max; function->_ptrcall_args_size = ptrcall_max; diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index 4b196ed420..909d88ee63 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -37,6 +37,17 @@ #include "gdscript_utility_functions.h" class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { + struct StackSlot { + Variant::Type type = Variant::NIL; + Vector<int> bytecode_indices; + + StackSlot() = default; + StackSlot(Variant::Type p_type) : + type(p_type) {} + }; + + const static int RESERVED_STACK = 3; // For self, class, and nil. + bool ended = false; GDScriptFunction *function = nullptr; bool debug_stack = false; @@ -47,15 +58,17 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { List<int> stack_identifiers_counts; Map<StringName, int> local_constants; + Vector<StackSlot> locals; + Vector<StackSlot> temporaries; + List<int> used_temporaries; + Map<Variant::Type, List<int>> temporaries_pool; + List<GDScriptFunction::StackDebug> stack_debug; List<Map<StringName, int>> block_identifier_stack; Map<StringName, int> block_identifiers; - int current_stack_size = 3; // First 3 spots are reserved for self, class, and nil. - int current_temporaries = 0; - int current_locals = 0; + int max_locals = 0; int current_line = 0; - int stack_max = 3; int instr_args_max = 0; int ptrcall_max = 0; @@ -102,7 +115,9 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { List<List<int>> match_continues_to_patch; void add_stack_identifier(const StringName &p_id, int p_stackpos) { - current_locals++; + if (locals.size() > max_locals) { + max_locals = locals.size(); + } stack_identifiers[p_id] = p_stackpos; if (debug_stack) { block_identifiers[p_id] = p_stackpos; @@ -116,7 +131,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { } void push_stack_identifiers() { - stack_identifiers_counts.push_back(current_locals); + stack_identifiers_counts.push_back(locals.size()); stack_id_stack.push_back(stack_identifiers); if (debug_stack) { Map<StringName, int> block_ids(block_identifiers); @@ -126,17 +141,16 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { } void pop_stack_identifiers() { - current_locals = stack_identifiers_counts.back()->get(); + int current_locals = stack_identifiers_counts.back()->get(); stack_identifiers_counts.pop_back(); stack_identifiers = stack_id_stack.back()->get(); stack_id_stack.pop_back(); #ifdef DEBUG_ENABLED - if (current_temporaries != 0) { - ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(current_temporaries)); + if (!used_temporaries.is_empty()) { + ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(used_temporaries.size())); } #endif - current_stack_size = current_locals + 3; // Keep the 3 reserved slots for self, class, and nil. - + locals.resize(current_locals); if (debug_stack) { for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) { GDScriptFunction::StackDebug sd; @@ -279,18 +293,6 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { return pos; } - void alloc_stack(int p_level) { - if (p_level >= stack_max) { - stack_max = p_level + 1; - } - } - - int increase_stack() { - int top = current_stack_size++; - alloc_stack(current_stack_size); - return top; - } - void alloc_ptrcall(int p_params) { if (p_params >= ptrcall_max) { ptrcall_max = p_params; @@ -308,9 +310,11 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { case Address::CONSTANT: return p_address.address | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); case Address::LOCAL_VARIABLE: - case Address::TEMPORARY: case Address::FUNCTION_PARAMETER: return p_address.address | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); + case Address::TEMPORARY: + temporaries.write[p_address.address].bytecode_indices.push_back(opcodes.size()); + return -1; case Address::NIL: return GDScriptFunction::ADDR_NIL; } @@ -392,7 +396,7 @@ public: virtual uint32_t add_local_constant(const StringName &p_name, const Variant &p_constant) override; virtual uint32_t add_or_get_constant(const Variant &p_constant) override; virtual uint32_t add_or_get_name(const StringName &p_name) override; - virtual uint32_t add_temporary() override; + virtual uint32_t add_temporary(const GDScriptDataType &p_type) override; virtual void pop_temporary() override; virtual void start_parameters() override; diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index cce4e856c7..214d0fefaa 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -71,7 +71,7 @@ public: virtual uint32_t add_local_constant(const StringName &p_name, const Variant &p_constant) = 0; virtual uint32_t add_or_get_constant(const Variant &p_constant) = 0; virtual uint32_t add_or_get_name(const StringName &p_name) = 0; - virtual uint32_t add_temporary() = 0; + virtual uint32_t add_temporary(const GDScriptDataType &p_type) = 0; virtual void pop_temporary() = 0; virtual void start_parameters() = 0; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index abbca899bd..7429e3cc0b 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -711,7 +711,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code case GDScriptParser::Node::UNARY_OPERATOR: { const GDScriptParser::UnaryOpNode *unary = static_cast<const GDScriptParser::UnaryOpNode *>(p_expression); - GDScriptCodeGenerator::Address result = codegen.add_temporary(); + GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(unary->get_datatype())); GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, unary->operand); if (r_error) { @@ -729,7 +729,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code case GDScriptParser::Node::BINARY_OPERATOR: { const GDScriptParser::BinaryOpNode *binary = static_cast<const GDScriptParser::BinaryOpNode *>(p_expression); - GDScriptCodeGenerator::Address result = codegen.add_temporary(); + GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(binary->get_datatype())); switch (binary->operation) { case GDScriptParser::BinaryOpNode::OP_LOGIC_AND: { diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 1b0beec0d4..c405eadb07 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -66,7 +66,7 @@ class GDScriptCompiler { } GDScriptCodeGenerator::Address add_temporary(const GDScriptDataType &p_type = GDScriptDataType()) { - uint32_t addr = generator->add_temporary(); + uint32_t addr = generator->add_temporary(p_type); return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::TEMPORARY, addr, p_type); } |