Initial pass at adding support for a templated emplacement new function. Added FunctionVisitor class to ICG to handle parsing constructors with arguments.

This commit is contained in:
Mark Herring 2024-09-19 23:38:31 -05:00
parent cca503a6ec
commit 64fabb22ec
18 changed files with 679 additions and 3 deletions

View File

View File

@ -0,0 +1,11 @@
import math
from trick.unit_test import *
print(f"alloc_test.atwargs = {alloc_test}")
#TRICK_EXPECT_EQ(alloc_test.atwargs.some_int, 0)
#TRICK_EXPECT_NEAR(alloc_test.atwargs.some_double, 0, 1e-6)
trick.add_read(4.0, """TRICK_EXPECT_EQ(alloc_test.atwargs.some_int, 0)""")
trick.add_read(4.0, """TRICK_EXPECT_NEAR(alloc_test.atwargs.some_double, 0, 1e-6)""")
trick.stop(5.0)

View File

@ -0,0 +1,33 @@
/************************TRICK HEADER*************************
PURPOSE:
(This sim test using tmm_alloc_args template function in a
simulation environment)
*************************************************************/
#include "sim_objects/default_trick_sys.sm"
##include "alloc_with_args.hh"
##include "trick/tmm_alloc_args.hh"
class AllocTestSimObject : public Trick::SimObject {
public:
AllocTestWithArguments* atwargs;
AllocTestSimObject() {
("initialization") init_alloc();
}
void init_alloc()
{
std::cout << "Entered init_alloc()\n";
std::cout << TrickTypeToString<AllocTestWithArguments>::getName() << "\n";
atwargs = tmm_alloc_args<AllocTestWithArguments>(0, 1.0);
std::cout << "Called tmm_alloc_args: " << atwargs << "\n";
}
};
AllocTestSimObject alloc_test ;

View File

@ -0,0 +1,3 @@
TRICK_CFLAGS += -I./models -I./build -g
TRICK_CXXFLAGS += -I./models -I./build -std=c++11 -g

View File

@ -0,0 +1,39 @@
/********************************* TRICK HEADER *******************************
PURPOSE: ( Test tmm_alloc_args in a sim environment )
LIBRARY DEPENDENCY:
(())
*******************************************************************************/
#include <iostream>
class AllocTestWithArguments {
friend class InputProcessor;
public:
AllocTestWithArguments()
:
some_int(0),
some_double(0.0)
{
}
AllocTestWithArguments(int in_int, double in_double)
:
some_int(in_int),
some_double(in_double)
{
std::cout << "AllocTestWithArguments constructor with: \n";
std::cout << "in_int: " << in_int << "\n";
std::cout << "in_double: " << in_double << "\n";
}
~AllocTestWithArguments() {
std::cout << "AllocTestWithArguments desctruct.\n";
}
int some_int;
double some_double;
};

View File

@ -50,6 +50,11 @@ void ClassValues::addFieldDescription(FieldDescription * in_fdes) {
field_name_to_info_map[in_fdes->getName()] = in_fdes ;
}
void ClassValues::addFunctionDescription(FunctionDescription * in_fdes)
{
function_descripts.push_back(in_fdes);
}
void ClassValues::addInheritedFieldDescriptions(std::vector<FieldDescription *> in_fdes,
unsigned int class_offset, bool virtual_inherited ) {
// Make a copy of all of the FieldDescription variables.
@ -179,6 +184,11 @@ void ClassValues::clearFieldDescription() {
field_descripts.clear() ;
}
void ClassValues::clearFunctionDescription() {
function_descripts.clear() ;
}
void ClassValues::addInheritedClass(std::string class_name) {
inherited_classes.push_back(class_name) ;
}

View File

@ -10,7 +10,7 @@
#include "ConstructValues.hh"
class FieldDescription ;
class FunctionDescription ;
/**
ClassValues holds information describing a class found with ICG. The
@ -34,6 +34,8 @@ class ClassValues : public ConstructValues {
/** Appends a single field to field_descripts */
void addFieldDescription(FieldDescription * in_fdes) ;
void addFunctionDescription(FunctionDescription* in_fdes);
/** Appends a vector of fields to field_descripts.
A vector comes from adding all inherited fields at once */
void addInheritedFieldDescriptions(std::vector<FieldDescription *>,
@ -44,8 +46,14 @@ class ClassValues : public ConstructValues {
return field_descripts ;
}
const std::vector<FunctionDescription*>& getFunctionDescriptions() {
return function_descripts ;
}
void clearFieldDescription() ;
void clearFunctionDescription() ;
/** Appends an inherited class name to the list this class inherits from */
void addInheritedClass( std::string class_name ) ;
@ -87,6 +95,8 @@ class ClassValues : public ConstructValues {
private:
std::vector< FieldDescription * > field_descripts ;
std::vector< FunctionDescription * > function_descripts ;
std::map< std::string , FieldDescription * > field_name_to_info_map ;
std::set< std::string > field_names_to_qualify ;

View File

@ -17,6 +17,8 @@
#include "CommentSaver.hh"
#include "PrintAttributes.hh"
#include "BraceMacro.hh"
#include "FunctionVisitor.hh"
extern llvm::cl::opt< int > debug_level ;
@ -115,6 +117,13 @@ bool CXXRecordVisitor::TraverseDecl(clang::Decl *d) {
fvis.TraverseFieldDecl(static_cast<clang::FieldDecl *>(d)) ;
cval.addFieldDescription(fvis.get_field_data()) ;
}
break;
case clang::Decl::CXXConstructor : {
FunctionVisitor fvis(ci , hsd , cs, pa, cval.getName()) ;
auto* ctor = static_cast<clang::CXXConstructorDecl *>(d);
fvis.TraverseDecl(ctor) ;
cval.addFunctionDescription(fvis.get_function_data()) ;
}
break ;
case clang::Decl::Friend : {
ClassValues temp_cv ;

View File

@ -0,0 +1,103 @@
#include "FunctionDescription.hh"
FunctionDescription::FunctionDescription() :
container_class(container_class),
is_inherited(false),
is_virtual_inherited(false),
is_static(false),
is_constructor(false),
is_default_constructor(false)
{
}
FunctionDescription::FunctionDescription(std::string& container_class) :
container_class(container_class),
is_inherited(false),
is_virtual_inherited(false),
is_static(false),
is_constructor(false),
is_default_constructor(false)
{
}
FunctionDescription::~FunctionDescription()
{
}
void FunctionDescription::setContainerClass(std::string& container_class)
{
this->container_class = container_class;
}
void FunctionDescription::setInherited(bool inherited)
{
this->is_inherited = inherited;
}
void FunctionDescription::setVirtualInherited(bool virtual_inherited)
{
this->is_virtual_inherited = virtual_inherited;
}
void FunctionDescription::setStatic(bool is_static)
{
this->is_static = is_static;
}
void FunctionDescription::setIsConstructor(bool is_constructor)
{
this->is_constructor = is_constructor;
}
void FunctionDescription::setReturnType(std::string return_type_name)
{
this->return_type_name = return_type_name;
}
std::string FunctionDescription::getMangledName()
{
std::string base = this->function_name;
for(auto& arg : this->function_args)
{
base += "_" + removePointerAndReference(arg.typeName);
}
return base;
}
void FunctionDescription::addFunctionArgument(FunctionArgument arg)
{
function_args.emplace_back(arg);
}
bool FunctionDescription::getIsPublic() const
{
return this->access == clang::AccessSpecifier::AS_public;
}
std::string FunctionDescription::removePointerAndReference(const std::string& typeStr)
{
std::string result = typeStr;
// Remove all '*' characters
result.erase(std::remove(result.begin(), result.end(), '*'), result.end());
// Remove all '&' characters
result.erase(std::remove(result.begin(), result.end(), '&'), result.end());
result.erase(std::remove(result.begin(), result.end(), ' '), result.end());
return result;
}

View File

@ -0,0 +1,107 @@
#ifndef __FUNCTION_DESCRIPTION_HH__
#define __FUNCTION_DESCRIPTION_HH__
#include <string>
#include <vector>
#include <utility>
#include "clang/Basic/Specifiers.h"
struct FunctionArgument
{
std::string typeName;
std::string argName;
bool isPointer;
bool isReference;
bool isConst;
};
class FunctionDescription
{
public:
FunctionDescription();
FunctionDescription(std::string& container_class);
~FunctionDescription();
void setReturnType(std::string return_type_name);
void setContainerClass(std::string& container_class);
void setInherited(bool inherited);
void setVirtualInherited(bool virtual_inherited);
void setStatic(bool is_static);
void setIsConstructor(bool is_constructor);
std::string getMangledName();
void addFunctionArgument(FunctionArgument arg);
std::string getReturnType() const { return return_type_name; }
inline std::vector<FunctionArgument>& getFunctionArgs();
inline void setFunctionName(std::string in_function_name);
inline void setAccess(clang::AccessSpecifier in_access);
inline void setIsDefaultConstructor(bool is_default);
inline bool getIsDefaultConstructor() const;
inline std::string getFunctionName() const;
inline std::string getContainerClass() const;
bool getIsPublic() const;
private:
/** Line number in current file where field is */
unsigned int line_no ;
/** Name of the class this field is in */
std::string container_class ;
std::string return_type_name ;
std::string function_name;
std::vector<FunctionArgument> function_args;
/** public/protected/private */
clang::AccessSpecifier access ;
/** is this function inherited from parent class */
bool is_inherited ;
/** is this function virtual inherited from parent class */
bool is_virtual_inherited ;
/** is this field declared static */
bool is_static ;
bool is_constructor ;
bool is_default_constructor ;
private:
std::string removePointerAndReference(const std::string& typeStr);
};
inline std::string FunctionDescription::getContainerClass() const {return container_class; }
inline std::vector<FunctionArgument>& FunctionDescription::getFunctionArgs() { return function_args; }
inline void FunctionDescription::setFunctionName(std::string in_function_name) { function_name = in_function_name; }
inline std::string FunctionDescription::getFunctionName() const { return function_name; }
inline void FunctionDescription::setAccess(clang::AccessSpecifier in_access) { access = in_access;}
inline bool FunctionDescription::getIsDefaultConstructor() const {return is_default_constructor;}
inline void FunctionDescription::setIsDefaultConstructor(bool is_default) { is_default_constructor = is_default; }
#endif // __FUNCTION_DESCRIPTION_HH__

View File

@ -0,0 +1,68 @@
#include "FunctionVisitor.hh"
#include "FunctionDescription.hh"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "llvm/Support/raw_ostream.h"
FunctionVisitor::FunctionVisitor(clang::CompilerInstance & in_ci ,
HeaderSearchDirs & in_hsd ,
CommentSaver & in_cs ,
PrintAttributes & in_pa ,
std::string container_class )
:
ci(in_ci) ,
hsd(in_hsd) ,
cs(in_cs) ,
pa(in_pa)
{
fdes = new FunctionDescription(container_class) ;
}
bool FunctionVisitor::VisitMethodDecl(clang::CXXMethodDecl* fd)
{
return true;
}
bool FunctionVisitor::VisitCXXConstructorDecl(clang::CXXConstructorDecl *ctor)
{
uint32_t num_params = ctor->getNumParams();
//Return type for constuctors is void
fdes->setReturnType(ctor->getReturnType().getAsString());
for(uint32_t i = 0; i < num_params; ++i)
{
FunctionArgument funcArg;
clang::ParmVarDecl *param = ctor->getParamDecl(i);
clang::QualType qt = param->getType();
std::string paramTypeStr = qt.getAsString();
// Get the parameter name
std::string paramName = param->getNameAsString();
funcArg.typeName = paramTypeStr;
funcArg.argName = paramName;
funcArg.isPointer = qt->isPointerType();
funcArg.isReference = qt->isReferenceType();
funcArg.isConst = qt.isConstQualified();
fdes->addFunctionArgument(funcArg);
}
fdes->setIsConstructor(true);
if(ctor->isDefaultConstructor())
{
fdes->setIsDefaultConstructor(true);
}
fdes->setAccess(ctor->getAccess());
fdes->setFunctionName(ctor->getParent()->getQualifiedNameAsString());
return true;
}

View File

@ -0,0 +1,47 @@
#ifndef __FUNCTION_VISITOR_HH__
#define __FUNCTION_VISITOR_HH__
#include "clang/Frontend/CompilerInstance.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DeclCXX.h"
#include "PrintAttributes.hh"
class CommentSaver ;
class HeaderSearchDirs ;
class SourceManager ;
class FunctionDescription ;
class FunctionVisitor : public clang::RecursiveASTVisitor<FunctionVisitor>
{
public:
FunctionVisitor(clang::CompilerInstance & in_ci ,
HeaderSearchDirs & in_hsd ,
CommentSaver & cs ,
PrintAttributes & in_pa ,
std::string container_class ) ;
bool VisitMethodDecl(clang::CXXMethodDecl* fd) ;
bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ctor);
inline FunctionDescription * get_function_data();
/** The compiler's source manager. Holds file/line info for everything. */
clang::CompilerInstance & ci ;
/** Holds all comments */
CommentSaver & cs ;
/** The header search directories */
HeaderSearchDirs & hsd ;
/** attributes printer */
PrintAttributes & pa ;
/** Holds the field information found, usually returned to caller of this visitor. */
FunctionDescription * fdes ;
};
inline FunctionDescription* FunctionVisitor::get_function_data() { return fdes ;}
#endif // __FUNCTION_VISITOR_HH__

View File

@ -16,6 +16,7 @@
#include "PrintFileContentsBase.hh"
#include "PrintFileContents10.hh"
#include "FieldDescription.hh"
#include "FunctionDescription.hh"
#include "HeaderSearchDirs.hh"
#include "CommentSaver.hh"
#include "ClassValues.hh"
@ -434,7 +435,7 @@ void PrintAttributes::printIOMakefile() {
makefile_io_src.open("build/Makefile_io_src") ;
makefile_io_src
<< "TRICK_IO_CXXFLAGS += -Wno-invalid-offsetof -Wno-old-style-cast -Wno-write-strings -Wno-unused-variable" << std::endl
<< "TRICK_IO_CXXFLAGS += -Wno-invalid-offsetof -Wno-old-style-cast -Wno-write-strings -Wno-unused-variable -Ibuild" << std::endl
<< std::endl
<< "ifeq ($(IS_CC_CLANG), 0)" << std::endl
<< " TRICK_IO_CXXFLAGS += -Wno-unused-local-typedefs -Wno-unused-but-set-variable" << std::endl
@ -646,3 +647,149 @@ bool PrintAttributes::isHeaderExcluded(const std::string& header, bool exclude_e
void PrintAttributes::markHeaderAsVisited(const std::string& header) {
visited_files.insert(header);
}
void PrintAttributes::writeTrickTypeToStructHeader()
{
std::set<std::string> class_names_to_print;
for(auto& pair : processed_classes)
{
bool foundMatch = false;
const std::set<std::string>& stringSet = pair.second;
for(const std::string& element : stringSet)
{
if(typedef_classes.find(element) != typedef_classes.end())
{
foundMatch = true;
}
else
{
if(element.find("::") == std::string::npos)
{
class_names_to_print.insert(element);
}
}
}
}
std::ofstream out_file;
out_file.open("build/trick/trick_type_to_string.hh");
out_file << "/********************************* TRICK HEADER *******************************\n";
out_file << "PURPOSE: ( Map types that trick knows about to strings using tempalte specialization )\n";
out_file << "LIBRARY DEPENDENCY:\n";
out_file << "(())\n";
out_file << "*******************************************************************************/\n";
out_file << "\n";
out_file << "#pragma once";
out_file << "\n\n";
out_file << "#include <string>\n";
out_file << "//Forward declarations\n";
for (auto class_name : class_names_to_print)
{
out_file << "class " << class_name << ";\n";
}
out_file << "\n\n";
out_file << "template<typename T>\n";
out_file << "struct TrickTypeToString { static std::string getName(); };\n";
out_file << "\n\n";
for (auto class_name : class_names_to_print)
{
out_file << "template<>\n";
out_file << "struct TrickTypeToString<" << class_name << ">\n";
out_file << "{\n";
out_file << " static std::string getName() \n";
out_file << " {\n";
out_file << " return \"" << class_name << "\";\n";
out_file << " }\n";
out_file << "};\n\n";
//out_file << "const std::string TrickTypeToString<" << class_name << ">::name = \"" << class_name << "\";\n";
out_file << "\n\n";
}
out_file.close();
}
void PrintAttributes::writeTemplateAllocHeader()
{
std::string build_trick = "build/trick/";
_mkdir(build_trick.c_str());
std::ofstream out_file;
out_file.open("build/trick/tmm_alloc_args.hh");
out_file << "#ifndef SWIG\n";
out_file << "/********************************* TRICK HEADER *******************************\n";
out_file << "PURPOSE: ( Simulate balls contacting boundaries. )\n";
out_file << "LIBRARY DEPENDENCY:\n";
out_file << "((trick/tmm_alloc_args.o))\n";
out_file << "*******************************************************************************/\n";
out_file << "#ifndef __TMM_ALLOC_ARGS_HH__\n";
out_file << "#define __TMM_ALLOC_ARGS_HH__\n";
out_file << "\n\n";
out_file << "#include <utility>\n\n";
out_file << "#include \"trick/trick_type_to_string.hh\"\n";
out_file << "#include <type_traits>\n\n";
out_file << "//trick includes\n";
out_file << "#include \"trick/MemoryManager.hh\"\n\n";
out_file << "template<typename... Ts>\n";
out_file << "struct make_void {\n";
out_file << " typedef void type;\n";
out_file << "};\n\n";
out_file << "template<typename... Ts>\n";
out_file << "using void_t = typename make_void<Ts...>::type;\n\n";
out_file << "template<typename T, typename = void_t<>>\n";
out_file << "struct has_getname : std::false_type {};\n";
out_file << "\n";
out_file << "template<typename T>\n";
out_file << "struct has_getname<T, void_t<decltype(std::declval<TrickTypeToString<T>>().getName())>> : std::true_type {};\n\n";
out_file << "template<typename T, typename ...Args>\n";
out_file << "typename std::enable_if<has_getname<T>::value, T*>::type\n";
out_file << "tmm_alloc_args(Args&&... args)\n";
out_file << "{\n";
out_file << " void* new_alloc = trick_MM->declare_var(TrickTypeToString<T>::getName().c_str());\n";
out_file << " return new (new_alloc) T(std::forward<Args>(args)...);\n";
out_file << "}\n\n";
out_file << "template<typename T, typename ...Args>\n";
out_file << "typename std::enable_if<!has_getname<T>::value, T*>::type\n";
out_file << "tmm_alloc_args(Args&&... args)\n";
out_file << "{\n";
out_file << " static_assert(true, \"You've attempted to call tmm_alloc_args using a type(T) that does not have an implemented template specialization.\");\n";
out_file << " return nullptr;\n";
out_file << "}\n\n";
out_file << "#endif //__TMM_ALLOC_ARGS_HH__\n";
out_file << "#endif // SWIG\n";
out_file.close();
out_file.open("build/trick/tmm_alloc_args.cc");
out_file << "#include \"trick/tmm_alloc_args.hh\"";
out_file.close();
}
void PrintAttributes::addTypedefClass(std::string typedef_class)
{
typedef_classes.insert(typedef_class);
}

View File

@ -65,8 +65,15 @@ class PrintAttributes {
void printSieEnum( EnumValues * ev ) ;
bool isHeaderExcluded(const std::string& header, bool exclude_ext_libs = true);
void markHeaderAsVisited(const std::string& header);
void writeTemplateAllocHeader();
void writeTrickTypeToStructHeader();
void addTypedefClass(std::string typedef_class);
protected:
const bool verboseBuild = (getenv("TRICK_VERBOSE_BUILD") || getenv("VERBOSE"));
@ -146,6 +153,8 @@ class PrintAttributes {
/** map of processed enums sorted by file */
std::map< std::string , std::set< std::string > > processed_enums ;
std::set<std::string> typedef_classes;
} ;
#endif

View File

@ -1,8 +1,10 @@
#include <algorithm>
#include <sstream>
#include <iterator>
#include "PrintFileContents10.hh"
#include "FieldDescription.hh"
#include "FunctionDescription.hh"
#include "ClassValues.hh"
#include "EnumValues.hh"
#include "Utilities.hh"
@ -37,6 +39,7 @@ void PrintFileContents10::printIOHeader(std::ostream & ostream , std::string hea
<< "#include \"trick/ClassSizeCheck.hh\"\n"
<< "#include \"trick/UnitsMap.hh\"\n"
<< "#include \"trick/checkpoint_stl.hh\"\n"
<< "#include \"trick/tmm_alloc_args.hh\"\n"
<< "#include \"" << header_file_name << "\"\n"
<< "\n" ;
}
@ -354,6 +357,7 @@ void PrintFileContents10::printClass( std::ostream & ostream , ClassValues * cv
print_io_src_delete(ostream, cv) ;
print_close_extern_c(ostream) ;
print_units_map(ostream, cv) ;
printTemplateConstructorWrapper(ostream, cv) ;
}
void PrintFileContents10::printEnum( std::ostream & ostream , EnumValues * ev ) {
@ -411,3 +415,71 @@ void PrintFileContents10::printStlFunction(const std::string& name, const std::s
<< " " << call << ";" << std::endl
<< "}" << std::endl ;
}
void PrintFileContents10::printTemplateConstructorWrapper(std::ostream & ostream , ClassValues * cv ) {
std::string name = cv->getFullyQualifiedMangledTypeName();
auto& function_descripts = cv->getFunctionDescriptions();
for (auto& function_descript : function_descripts) {
if(!function_descript->getIsDefaultConstructor() && function_descript->getIsPublic())
{
//Create mangled name for this constructor
std::string mangled_name = function_descript->getMangledName();
if(mangled_name.find("Trick::") == std::string::npos && mangled_name.find("std::") == std::string::npos && mangled_name.find("er7_utils::") == std::string::npos)
{
//Since these are constructors, we don't want the return type since it will be void - thanks clang!
ostream << function_descript->getContainerClass() << "* " << mangled_name << "(";
auto arguments = function_descript->getFunctionArgs();
std::string arg_base = "arg_";
size_t arg_counter = 0;
auto it = arguments.begin();
auto end = arguments.end();
while(it != end)
{
auto argument = *it;
ostream << argument.typeName;
ostream << " " << arg_base + std::to_string(arg_counter);
++it;
++arg_counter;
if (it != end) {
ostream << ", ";
}
}
ostream << ")\n{\n";
ostream << " return tmm_alloc_args<" + function_descript->getFunctionName() + ">(";
for (size_t i = 0; i < arguments.size(); ++i)
{
ostream << "arg_" + std::to_string(i);
if ( i != arguments.size() - 1)
{
ostream << ", ";
}
}
ostream << ");\n";
ostream << "}\n";
}
ostream << "\n\n";
}
}
}

View File

@ -102,6 +102,8 @@ class PrintFileContents10 : public PrintFileContentsBase {
void print_clear_stl(std::ostream & outfile , FieldDescription * fdes , ClassValues * in_class) ;
void printStlFunction(const std::string& name, const std::string& parameters, const std::string& call, std::ostream& ostream, FieldDescription& fieldDescription, ClassValues& classValues);
void printTemplateConstructorWrapper(std::ostream & ostream , ClassValues * cv ) ;
} ;
#endif

View File

@ -136,6 +136,8 @@ bool TypedefVisitor::VisitTypedefDecl(clang::TypedefDecl *td) {
typedef_location = td->getSourceRange() ;
typedef_decl_context = td->getDeclContext() ;
this->pa.addTypedefClass(typedef_name) ;
return true;
}

View File

@ -340,6 +340,10 @@ int main(int argc, char * argv[]) {
// Print the list of headers that have the ICG:(No) comment
printAttributes.printICGNoFiles();
printAttributes.writeTemplateAllocHeader();
printAttributes.writeTrickTypeToStructHeader();
if (icgDiagConsumer->error_in_user_code) {
std::cout << color(ERROR, "Trick build was terminated due to error in user code!") << std::endl;
exit(-1);