jak-project/goalc/compiler/compilation/Static.cpp
water111 a45d180f2c
Try to speed up the build (#106)
* first attempt

* attempt 2

* windows and formatting fix
2020-10-29 21:27:52 -04:00

141 lines
5.2 KiB
C++

/*!
* @file Static.cpp
* Compiler helper functions for creating static data.
* This is the front end for things in StaticObject.cpp
*/
#include "goalc/compiler/Compiler.h"
#include "third-party/fmt/core.h"
namespace {
bool integer_fits(s64 in, int size, bool is_signed) {
switch (size) {
case 1:
if (is_signed) {
return in >= INT8_MIN && in <= INT8_MAX;
} else {
return in >= 0 && in <= UINT8_MAX;
}
case 2:
if (is_signed) {
return in >= INT16_MIN && in <= INT16_MAX;
} else {
return in >= 0 && in <= UINT16_MAX;
}
case 4:
if (is_signed) {
return in >= INT32_MIN && in <= INT32_MAX;
} else {
return in >= 0 && in <= UINT32_MAX;
}
case 8:
return true;
default:
assert(false);
}
}
} // namespace
Val* Compiler::compile_new_static_structure_or_basic(const goos::Object& form,
const TypeSpec& type,
const goos::Object& _field_defs,
Env* env) {
auto fe = get_parent_env_of_type<FunctionEnv>(env);
std::unique_ptr<StaticStructure> obj;
if (is_basic(type)) {
obj = std::make_unique<StaticBasic>(MAIN_SEGMENT, type.base_type());
} else {
// if we ever find this type of static data outside of MAIN_SEGMENT, we can create an option
// in the new form to pick the segment.
obj = std::make_unique<StaticStructure>(MAIN_SEGMENT);
}
auto type_info = dynamic_cast<StructureType*>(m_ts.lookup_type(type));
assert(type_info); // should always be at least a structure.
obj->data.resize(type_info->get_size_in_memory());
// the file env will end up owning the obj.
auto result = fe->alloc_val<StaticVal>(obj.get(), type);
auto* field_defs = &_field_defs;
while (!field_defs->is_empty_list()) {
auto field_name_def = symbol_string(pair_car(*field_defs));
field_defs = &pair_cdr(*field_defs);
auto field_value = pair_car(*field_defs);
field_defs = &pair_cdr(*field_defs);
if (field_name_def.at(0) != ':') {
throw_compile_error(form,
"expected field def name to start with :, instead got " + field_name_def);
}
field_name_def = field_name_def.substr(1);
auto field_info = m_ts.lookup_field_info(type_info->get_name(), field_name_def);
if (field_info.field.is_dynamic() || field_info.field.is_inline() ||
field_info.field.is_array()) {
throw_compile_error(form, "Static objects not yet implemented for dynamic/inline/array");
}
auto field_offset = field_info.field.offset();
assert(field_info.needs_deref); // for now...
auto deref_info = m_ts.get_deref_info(m_ts.make_pointer_typespec(field_info.type));
auto field_size = deref_info.load_size;
assert(field_offset + field_size <= int(obj->data.size()));
if (is_integer(field_info.type)) {
s64 value = 0;
if (!try_getting_constant_integer(field_value, &value, env)) {
throw_compile_error(form,
fmt::format("Field {} is an integer, but the value given couldn't be "
"converted to an integer at compile time.",
field_name_def));
}
if (!integer_fits(value, deref_info.load_size, deref_info.sign_extend)) {
throw_compile_error(
form, fmt::format("Field {} is set to a compile time integer value of {} which would "
"overflow (size {} signed {})",
field_name_def, value, deref_info.load_size, deref_info.sign_extend));
}
if (field_size == 1 || field_size == 2 || field_size == 4 || field_size == 8) {
memcpy(obj->data.data() + field_offset, &value, field_size);
} else {
// not sure how we can create 128-bit integer constants at this point...
assert(false);
}
} else if (is_basic(field_info.type)) {
if (is_quoted_sym(field_value)) {
obj->add_symbol_record(quoted_sym_as_string(field_value), field_offset);
assert(deref_info.mem_deref);
assert(deref_info.can_deref);
assert(deref_info.load_size == 4);
// the linker needs to see a -1 in order to know to insert a symbol pointer
// instead of just the symbol table offset.
u32 linker_val = 0xffffffff;
memcpy(obj->data.data() + field_offset, &linker_val, 4);
} else {
throw_compile_error(
form, "Setting a basic field to anything other than a symbol is currently unsupported");
}
} else if (is_float(field_info.type)) {
float value = 0.f;
if (!try_getting_constant_float(field_value, &value, env)) {
throw_compile_error(form, fmt::format("Field {} is a float, but the value given couldn't "
"be converted to a float at compile time.",
field_name_def));
}
memcpy(obj->data.data() + field_offset, &value, sizeof(float));
}
else {
assert(false); // for now
}
}
auto fie = get_parent_env_of_type<FileEnv>(env);
fie->add_static(std::move(obj));
return result;
}