trick/trick_source/codegen/Interface_Code_Gen/PrintFileContents10.cpp
ninotarantino 91a348d7e0
Fix several ICG class template bugs (#1871)
* Fix several bugs with processing templates in ICG

- Fixed an issue where io_src code for some templates was being placed in the
  wrong file.
- Fixed an issue with templates being instantiated with templates as parameters.
- Fixed an issue with templates that instantiate templates.

Added additional tests to cover these cases.

* Moved the list of template argument header dependencies from ClassValues to PrintFileContents10 so they can be printed to the io_ file regardless of the order in which class info is printed.

* Moved the list of template argument header dependencies from ClassValues to PrintFileContents10 so they can be printed to the io_ file regardless of the order in which class info is printed.

Moved the list of template argument header dependencies from ClassValues to PrintFileContents10 so they can be printed to the io_ file regardless of the order in which class info is printed.

* Added support to handle template enum class type argument and removed some commented code.

Added support to handle template enum class type argument and removed some commented code.

---------

Co-authored-by: Hong Chen <hchen99@users.noreply.github.com>
2025-04-29 15:30:49 -05:00

440 lines
20 KiB
C++

#include <algorithm>
#include <sstream>
#include "PrintFileContents10.hh"
#include "FieldDescription.hh"
#include "ClassValues.hh"
#include "EnumValues.hh"
#include "Utilities.hh"
extern llvm::cl::opt< bool > global_compat15 ;
PrintFileContents10::PrintFileContents10() {}
/** Prints the io_src header information */
void PrintFileContents10::printIOHeader(std::ostream & ostream , std::string header_file_name) {
if ( ! header_file_name.compare("S_source.hh") ) {
header_file_name = "../S_source.hh" ;
} else {
header_file_name = almostRealPath(header_file_name.c_str()) ;
}
ostream << "/**\n"
<< " * This file was automatically generated by the ICG based on the file:\n"
<< " * " << header_file_name << "\n"
<< " * This file contains database parameter declarations specific to the\n"
<< " * data structures and enumerated types declared in the above file.\n"
<< " * These database parameters are used by the Trick input and\n"
<< " * data recording processors to gain access to important simulation\n"
<< " * variable information.\n"
<< " */\n"
<< "\n"
<< "#define TRICK_IN_IOSRC\n"
<< "#include <stdlib.h>\n"
<< "#include \"trick/MemoryManager.hh\"\n"
<< "#include \"trick/attributes.h\"\n"
<< "#include \"trick/parameter_types.h\"\n"
<< "#include \"trick/ClassSizeCheck.hh\"\n"
<< "#include \"trick/UnitsMap.hh\"\n"
<< "#include \"trick/checkpoint_stl.hh\"\n"
<< "#include \"" << header_file_name << "\"\n"
<< "\n" ;
}
/** Prints enumeration attributes */
void PrintFileContents10::print_enum_attr(std::ostream & ostream , EnumValues * e ) {
print_open_extern_c(ostream) ;
ostream << "ENUM_ATTR enum" << e->getFullyQualifiedTypeName("__") << "[] = {\n" ;
std::string name = e->getNamespacesAndContainerClasses();
for (auto& pair : e->getPairs()) {
ostream << "{\"" << name << pair.first << "\", " << pair.second << ", 0x0},\n" ;
}
ostream << "{\"\", 0, 0x0}\n};\n" ;
print_close_extern_c(ostream) ;
}
/** Prints attributes for a field */
void PrintFileContents10::print_field_attr(std::ostream & ostream , FieldDescription & fdes ) {
int array_dim ;
ostream << "{\"" << fdes.getName() << "\"" // name
<< ", \"" << fdes.getFullyQualifiedMangledTypeName("__") << "\"" // type_name
<< ", \"" << fdes.getUnits() << "\"" // units
<< ", \"\", \"\"," << std::endl // alias, user_defined
<< " \"" << fdes.getDescription() << "\"," << std::endl // description
<< " " << fdes.getIO() // io
<< "," << fdes.getEnumString() ; // type
// There are several cases when printing the size of a variable.
if ( fdes.isBitField() ) {
// bitfields are handled in 4 byte (32 bit) chunks
ostream << ", 4" ;
} else if ( fdes.isRecord() or fdes.isEnum() or fdes.getTypeName().empty() ) {
// records enums use io_src_get_size. The sentinel has no typename
ostream << ", 0" ;
} else {
// print size of the underlying type
ostream << ", sizeof(" << fdes.getTypeName() << ")" ;
}
ostream << ", 0, 0, Language_CPP" ; // range_min, range_max, language
// mods (see attributes.h for descriptions)
ostream << ", " << fdes.isReference() + (fdes.isStatic() << 1) + (fdes.isDashDashUnits() << 2) + (fdes.isReference() ? (((fdes.getFieldWidth() / 8) & 0x3F) << 3) : 0) << "," << std::endl ; // mods
if ( fdes.isBitField() ) {
// For bitfields we need the offset to start on 4 byte boundaries because that is what our
// insert and extract bitfield routines work with.
ostream << " " << (fdes.getFieldOffset() - (fdes.getFieldOffset() % 32)) / 8 ; // offset
} else {
ostream << " " << (fdes.getFieldOffset() / 8) ; // offset
}
ostream << ", NULL" ; // attr
ostream << ", " << fdes.getNumDims() ; // num_index
ostream << ", {" ;
if ( fdes.isBitField() ) {
ostream << "{" << fdes.getBitFieldWidth() ; // size of bitfield
ostream << ", " << 32 - (fdes.getFieldOffset() % 32) - fdes.getBitFieldWidth() << "}" ; // start bit
} else {
array_dim = fdes.getArrayDim(0) ;
if ( array_dim < 0 ) array_dim = 0 ;
ostream << "{" << array_dim << ", 0}" ; // index 0
}
unsigned int ii ;
for ( ii = 1 ; ii < 8 ; ii++ ) {
array_dim = fdes.getArrayDim(ii) ;
if ( array_dim < 0 ) array_dim = 0 ;
ostream << ", {" << array_dim << ", 0}" ; // indexes 1 through 7
}
ostream << "}," << std::endl ;
ostream << " NULL, NULL, NULL, NULL" ;
ostream << "}" ;
}
/** Prints class attributes */
void PrintFileContents10::print_class_attr(std::ostream & ostream , ClassValues * c ) {
print_open_extern_c(ostream) ;
ostream << "ATTRIBUTES attr" << c->getFullyQualifiedMangledTypeName("__") << "[] = {" << std::endl ;
for (FieldDescription* fieldDescription : getPrintableFields(*c)) {
print_field_attr(ostream, *fieldDescription) ;
ostream << "," << std::endl ;
}
// Print an empty sentinel attribute at the end of the class.
FieldDescription new_fdes(std::string("")) ;
print_field_attr(ostream, new_fdes) ;
ostream << " };" << std::endl ;
print_close_extern_c(ostream) ;
}
/** Prints init_attr function for each class */
void PrintFileContents10::print_field_init_attr_stmts( std::ostream & ostream , FieldDescription * fdes ,
ClassValues * cv , unsigned int index ) {
const std::string className = cv->getName();
const std::string mangledClassName = cv->getMangledTypeName();
const std::string fieldName = fdes->getName();
const std::string fullyQualifiedClassNameColons = cv->getFullyQualifiedTypeName();
const std::string fullyQualifiedMangledClassNameColons = cv->getFullyQualifiedMangledTypeName();
const std::string fullyQualifiedMangledClassNameUnderscores = cv->getFullyQualifiedMangledTypeName("__");
std::ostringstream oss;
oss << " attr" << fullyQualifiedMangledClassNameUnderscores << "[" << index << "].";
const std::string prefix = oss.str();
if ( fdes->isStatic() ) {
ostream << prefix << "offset = (long)(void *)&" << fullyQualifiedClassNameColons << "::" << fieldName << " ;\n" ;
}
else if ( global_compat15 or cv->isCompat15() ) {
if ( fdes->isBitField() ) {
ostream << prefix << "offset = " << fdes->getBitFieldByteOffset() << " ;\n" ;
ostream << prefix << "size = sizeof(unsigned int) ;\n" ;
}
else if ( fdes->isVirtualInherited() ) {
// For virtual inherited fields, we need to use the base class offset.
// Only print offset for public inherited fields.
// Protected and private inherited fields are not accessible.
if (fdes->getAccess() == clang::AS_public) {
ostream << prefix << "offset = " << fdes->getBaseClassOffset() << " + offsetof(" << fdes->getContainerClass() << ", " << fieldName << ") ;\n" ;
}
}
else if ( mangledClassName != className ) {
ostream << prefix << "offset = " << "offsetof(" << mangledClassName << ", " << fieldName << ") ;\n" ;
}
else {
ostream << prefix << "offset = " << "offsetof(" << fullyQualifiedMangledClassNameColons << ", " << fieldName << ") ;\n" ;
}
}
if ( fdes->isSTL() ) {
auto print = [&](const std::string& field) {
ostream << prefix << field << " = " << field << "_" << fullyQualifiedMangledClassNameUnderscores + "_" + sanitize(fieldName) + " ;\n";
};
if ( fdes->isCheckpointable() ) {
print("checkpoint_stl");
print("post_checkpoint_stl");
}
if ( fdes->isRestorable() ) {
print("restore_stl");
if ( fdes->hasSTLClear() ) {
print("clear_stl");
}
}
}
if ( fdes->isRecord() or fdes->isEnum() ) {
ostream << " trick_MM->add_attr_info(std::string(attr" << fullyQualifiedMangledClassNameUnderscores << "[" << index << "].type_name) , &attr" << fullyQualifiedMangledClassNameUnderscores << "[" << index << "], __FILE__ , __LINE__ ) ;\n" ;
}
}
/** Prints add_attr_info statements for each inherited class */
void PrintFileContents10::print_inherited_add_attr_info( std::ostream & ostream , ClassValues * cv ) {
auto inheritedClasses = cv->getInheritedClasses();
if ( inheritedClasses.size() > 0 ) {
ostream << "\n ATTRIBUTES temp_attr ;\n\n" ;
}
for ( auto& inheritedClass : inheritedClasses ) {
ostream << " trick_MM->add_attr_info( std::string(\"" << inheritedClass << "\"), &temp_attr , __FILE__ , __LINE__ ) ;\n" ;
}
}
/** Prints init_attr function for each class */
void PrintFileContents10::print_init_attr_func( std::ostream & ostream , ClassValues * cv ) {
cv->printOpenNamespaceBlocks(ostream) ;
ostream << "\nvoid init_attr" << cv->getFullyQualifiedMangledTypeName("__") << "() {\n\n"
<< " static int initialized ;\n"
<< " if (initialized) {\n"
<< " return;\n"
<< " }\n"
<< " initialized = 1;\n\n" ;
unsigned int ii = 0;
for ( FieldDescription* field : getPrintableFields(*cv) ) {
print_field_init_attr_stmts(ostream, field, cv, ii++) ;
}
print_inherited_add_attr_info(ostream, cv ) ;
ostream << "}\n" ;
cv->printCloseNamespaceBlocks(ostream) ;
}
/** Prints the io_src_sizeof function for enumerations */
void PrintFileContents10::print_enum_io_src_sizeof( std::ostream & ostream , EnumValues * ev ) {
print_open_extern_c(ostream) ;
ostream << "size_t io_src_sizeof_" << ev->getFullyQualifiedName("__") << "( void ) {\n" ;
if ( ev->getHasDefinition() ) {
ostream << " return sizeof(" << ev->getFullyQualifiedName() << ")" ;
} else {
ostream << " return sizeof(int)" ;
}
ostream << ";\n}\n" ;
print_close_extern_c(ostream) ;
}
/** Prints the C linkage init_attr function */
void PrintFileContents10::print_init_attr_c_intf( std::ostream & ostream , ClassValues * cv ) {
ostream << "void init_attr" << cv->getFullyQualifiedMangledTypeName("__") << "_c_intf() {\n " ;
cv->printNamespaces( ostream, "::" ) ;
ostream << "init_attr" << cv->getFullyQualifiedMangledTypeName("__") << "() ;\n"
<< "}\n\n" ;
}
/** Prints the io_src_sizeof function */
void PrintFileContents10::print_io_src_sizeof( std::ostream & ostream , ClassValues * cv ) {
ostream << "size_t io_src_sizeof_" << cv->getFullyQualifiedMangledTypeName("__") << "() {\n" ;
ostream << " return sizeof(" << cv->getFullyQualifiedNameIfEqual() << ") ;\n}\n\n" ;
}
/** Prints the io_src_allocate function */
void PrintFileContents10::print_io_src_allocate( std::ostream & ostream , ClassValues * cv ) {
if ( cv->isPOD() or ( !cv->isAbstract() and cv->getHasDefaultConstructor()) ) {
const std::string name = cv->getFullyQualifiedNameIfEqual();
ostream << "void* io_src_allocate_" << cv->getFullyQualifiedMangledTypeName("__") << "(int num) {\n" ;
ostream << " " << name << "* temp = (" << name << "*)calloc(num, sizeof(" << name << "));\n" ;
if ( ! cv->isPOD() ) {
ostream << " for (int ii = 0; ii < num; ++ii) {\n" ;
ostream << " new(&temp[ii]) " << name << "();\n }\n" ;
}
ostream << " return (void*)temp;\n" << "}\n\n" ;
}
}
/** Prints the io_src_allocate function */
void PrintFileContents10::print_io_src_destruct( std::ostream & ostream , ClassValues * cv ) {
if ( cv->getHasPublicDestructor() ) {
ostream << "void io_src_destruct_" << cv->getFullyQualifiedMangledTypeName("__") << "(void* address __attribute__((unused)), int num __attribute__((unused))) {\n" ;
if ( ! cv->isPOD() ) {
// Add a using statement so we can call the destructor without fully qualifying it.
auto namespaces = cv->getNamespaces();
if (namespaces.size()) {
ostream << " using namespace " ;
auto last = namespaces[namespaces.size() - 1];
for (auto& name : namespaces) {
ostream << name;
if (name != last) {
ostream << "::";
}
}
ostream << ";\n " ;
}
const std::string name = cv->getName();
const std::string qualifiedName = cv->getFullyQualifiedNameIfEqual();
ostream << qualifiedName << "* temp = (" << qualifiedName << "*)address;\n" ;
if ( cv->getMangledTypeName() == name ) {
ostream << " for (int ii = 0; ii < num; ++ii) {\n"
<< " temp[ii].~" << name << "();\n"
<< " }\n" ;
}
}
ostream << "}\n\n" ;
}
}
void PrintFileContents10::print_io_src_delete( std::ostream & ostream , ClassValues * cv ) {
if ( cv->getHasPublicDestructor() ) {
ostream << "void io_src_delete_" << cv->getFullyQualifiedMangledTypeName("__") << "(void* address" ;
if ( ! cv->isPOD() ) {
ostream << ") {\n delete (" << cv->getFullyQualifiedNameIfEqual() << "*)address;\n" ;
}
else {
ostream << " __attribute__((unused))) {" ;
}
ostream << "}\n" ;
}
}
void PrintFileContents10::print_checkpoint_stl(std::ostream & ostream , FieldDescription * fdes , ClassValues * cv ) {
printStlFunction("checkpoint", "void* start_address, const char* obj_name , const char* var_name", "checkpoint_stl(*stl, obj_name, var_name)", ostream, *fdes, *cv);
}
void PrintFileContents10::print_post_checkpoint_stl(std::ostream & ostream , FieldDescription * fdes , ClassValues * cv ) {
printStlFunction("post_checkpoint", "void* start_address, const char* obj_name , const char* var_name", "delete_stl(*stl, obj_name, var_name)", ostream, *fdes, *cv);
}
void PrintFileContents10::print_restore_stl(std::ostream & ostream , FieldDescription * fdes , ClassValues * cv ) {
printStlFunction("restore", "void* start_address, const char* obj_name , const char* var_name", "restore_stl(*stl, obj_name, var_name)",ostream, *fdes, *cv);
}
void PrintFileContents10::print_clear_stl(std::ostream & ostream , FieldDescription * fdes , ClassValues * cv ) {
printStlFunction("clear", "void* start_address", "stl->clear()",ostream, *fdes, *cv);
}
void PrintFileContents10::print_stl_helper(std::ostream & ostream , ClassValues * cv ) {
std::vector<FieldDescription*> fieldDescriptions = getPrintableFields(*cv, 0x3 << 2);
fieldDescriptions.erase(std::remove_if(fieldDescriptions.begin(), fieldDescriptions.end(), [](FieldDescription* field) {return !field->isSTL();}), fieldDescriptions.end());
if (!fieldDescriptions.size()) {
return;
}
print_open_extern_c(ostream) ;
for (FieldDescription* field : fieldDescriptions) {
if (field->isCheckpointable()) {
print_checkpoint_stl(ostream, field, cv) ;
print_post_checkpoint_stl(ostream, field, cv) ;
}
if (field->isRestorable()) {
print_restore_stl(ostream, field, cv) ;
if (field->hasSTLClear()) {
print_clear_stl(ostream, field, cv) ;
}
}
}
print_close_extern_c(ostream) ;
}
void PrintFileContents10::printClass( std::ostream & ostream , ClassValues * cv ) {
//print_template_argument_header_deps(ostream, cv) ;
print_template_argument_header_dependencies(ostream, cv->getFileName()) ;
print_class_attr(ostream, cv) ;
print_stl_helper(ostream, cv) ;
print_init_attr_func(ostream, cv) ;
ostream << std::endl;
print_open_extern_c(ostream) ;
print_init_attr_c_intf(ostream, cv) ;
print_io_src_sizeof(ostream, cv) ;
print_io_src_allocate(ostream, cv) ;
print_io_src_destruct(ostream, cv) ;
print_io_src_delete(ostream, cv) ;
print_close_extern_c(ostream) ;
print_units_map(ostream, cv) ;
}
void PrintFileContents10::printEnum( std::ostream & ostream , EnumValues * ev ) {
print_enum_attr(ostream, ev) ;
print_enum_io_src_sizeof(ostream, ev) ;
}
void PrintFileContents10::printClassMapHeader( std::ostream & ostream , std::string function_name ) {
ostream <<
"/*\n"
" * This file was automatically generated by the ICG\n"
" * This file contains the map from class/struct names to attributes\n"
" */\n\n"
"#include <map>\n"
"#include <string>\n\n"
"#include \"trick/AttributesMap.hh\"\n"
"#include \"trick/EnumAttributesMap.hh\"\n"
"#include \"trick/attributes.h\"\n\n"
"void " << function_name << "() {\n\n"
" Trick::AttributesMap * class_attribute_map = Trick::AttributesMap::attributes_map();\n\n" ;
}
void PrintFileContents10::printClassMap( std::ostream & ostream , ClassValues * cv ) {
std::string name = cv->getFullyQualifiedMangledTypeName("__");
ostream << " // " << cv->getFileName() << std::endl
<< " extern ATTRIBUTES attr" << name << "[] ;" << std::endl
<< " class_attribute_map->add_attr(\"" << cv->getFullyQualifiedMangledTypeName() << "\" , attr" << name << ") ;" << std::endl ;
}
void PrintFileContents10::printClassMapFooter( std::ostream & ostream ) {
ostream << "}" << std::endl << std::endl ;
}
void PrintFileContents10::printEnumMapHeader( std::ostream & ostream , std::string function_name ) {
ostream << "void " << function_name << "() {\n"
<< " Trick::EnumAttributesMap* enum_attribute_map __attribute__((unused)) = Trick::EnumAttributesMap::attributes_map();\n\n" ;
}
void PrintFileContents10::printEnumMap( std::ostream & ostream , EnumValues * ev ) {
std::string name = ev->getFullyQualifiedTypeName("__");
ostream << " extern ENUM_ATTR enum" << name << "[];" << std::endl
<< " enum_attribute_map->add_attr(\"" << ev->getFullyQualifiedTypeName() << "\", enum" << name << ");" << std::endl ;
}
void PrintFileContents10::printEnumMapFooter( std::ostream & ostream ) {
ostream << "}" << std::endl << std::endl ;
}
void PrintFileContents10::printStlFunction(const std::string& name, const std::string& parameters, const std::string& call, std::ostream& ostream, FieldDescription& fieldDescription, ClassValues& classValues) {
const std::string typeName = fieldDescription.getTypeName();
const std::string functionName = name + "_stl";
ostream << "void " << functionName << "_" << classValues.getFullyQualifiedMangledTypeName("__") << "_" << sanitize(fieldDescription.getName())
<< "(" << parameters << ") {" << std::endl
<< " " << typeName << "* stl = reinterpret_cast<" << typeName << "*>(start_address);" << std::endl
<< " " << call << ";" << std::endl
<< "}" << std::endl ;
}
void PrintFileContents10::addTemplateArgumentHeaderDependency(const std::string& header, const std::string& dependency) {
if (!dependency.empty()) {
HeaderInfo header_dependency(dependency);
template_argument_header_dependencies[header].insert(header_dependency);
}
}
void PrintFileContents10::print_template_argument_header_dependencies(std::ostream & outfile, std::string header_file_name) {
auto it = template_argument_header_dependencies.find(header_file_name);
if (it != template_argument_header_dependencies.end()) {
for (const auto& headerInfo : it->second) {
if (!headerInfo.printed && headerInfo.header_path != header_file_name) {
outfile << "#include \"" << headerInfo.header_path << "\"\n";
const_cast<HeaderInfo&>(headerInfo).printed = true;
}
}
}
}