# HG changeset patch # User Tomas Lindquist Olsen # Date 1239818785 -7200 # Node ID 79758fd2f48ad75fa2f6a2a521d108d749f0cf11 # Parent 08f87d8cd101f2d285ad791b93fef324883683c3 Added Doxygen file. Completely seperated type and symbol generation. Should fix a lot of bugs, but is not yet 100% complete. diff -r 08f87d8cd101 -r 79758fd2f48a Doxyfile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Doxyfile Wed Apr 15 20:06:25 2009 +0200 @@ -0,0 +1,1473 @@ +# Doxyfile 1.5.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = LDC + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doxy + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = dmd dmd/root gen ir + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c *.cpp *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Namespace. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# Qt Help Project / Virtual Folders. + +QHP_VIRTUAL_FOLDER = doc + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file . + +QHG_LOCATION = + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = NONE + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 8 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = NO + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff -r 08f87d8cd101 -r 79758fd2f48a dmd/attrib.h --- a/dmd/attrib.h Mon Apr 13 17:42:36 2009 +0200 +++ b/dmd/attrib.h Wed Apr 15 20:06:25 2009 +0200 @@ -115,10 +115,6 @@ void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); const char *kind(); - -#if IN_LLVM - void codegen(Ir*); -#endif }; struct PragmaDeclaration : AttribDeclaration diff -r 08f87d8cd101 -r 79758fd2f48a dmd/expression.c --- a/dmd/expression.c Mon Apr 13 17:42:36 2009 +0200 +++ b/dmd/expression.c Wed Apr 15 20:06:25 2009 +0200 @@ -55,7 +55,6 @@ #include "hdrgen.h" #include "parse.h" -Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim); Expression *expandVar(int result, VarDeclaration *v); #define LOGSEMANTIC 0 diff -r 08f87d8cd101 -r 79758fd2f48a dmd/func.c --- a/dmd/func.c Mon Apr 13 17:42:36 2009 +0200 +++ b/dmd/func.c Wed Apr 15 20:06:25 2009 +0200 @@ -84,6 +84,25 @@ // LDC isArrayOp = false; allowInlining = false; + + // function types in ldc don't merge if the context parameter differs + // so we actually don't care about the function declaration, but only + // what kind of context parameter it has. + // however, this constructor is usually called from the parser, which + // unfortunately doesn't provide the information needed to get to the + // aggregate type. So we have to stick with the FuncDeclaration and + // just be sure we don't actually rely on the symbol it points to, + // but rather just the type of its context parameter. + // this means some function might have a function type pointing to + // another function declaration + + if (type) + { + assert(type->ty == Tfunction && "invalid function type"); + TypeFunction* tf = (TypeFunction*)type; + if (tf->funcdecl == NULL) + tf->funcdecl = this; + } #endif } diff -r 08f87d8cd101 -r 79758fd2f48a dmd/lexer.c --- a/dmd/lexer.c Mon Apr 13 17:42:36 2009 +0200 +++ b/dmd/lexer.c Wed Apr 15 20:06:25 2009 +0200 @@ -8,7 +8,9 @@ // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. +#if IN_LLVM #include +#endif /* Lexical Analyzer */ diff -r 08f87d8cd101 -r 79758fd2f48a dmd/mtype.c --- a/dmd/mtype.c Mon Apr 13 17:42:36 2009 +0200 +++ b/dmd/mtype.c Wed Apr 15 20:06:25 2009 +0200 @@ -350,14 +350,14 @@ * Name mangling. */ -void Type::toDecoBuffer(OutBuffer *buf) +void Type::toDecoBuffer(OutBuffer *buf, bool mangle) { buf->writeByte(mangleChar[ty]); if (next) { assert(next != this); //printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty); - next->toDecoBuffer(buf); + next->toDecoBuffer(buf, mangle); } } @@ -434,7 +434,7 @@ if (next) next = next->merge(); - toDecoBuffer(&buf); + toDecoBuffer(&buf, false); sv = stringtable.update((char *)buf.data, buf.offset); if (sv->ptrvalue) { t = (Type *) sv->ptrvalue; @@ -444,7 +444,11 @@ else { sv->ptrvalue = this; - deco = sv->lstring.string; + + OutBuffer mangle; + toDecoBuffer(&mangle, true); + mangle.writeByte(0); + deco = mem.strdup((char *)mangle.data); //printf("new value, deco = '%s' %p\n", t->deco, t->deco); } } @@ -743,7 +747,7 @@ buf.writeByte(mangleChar[((TypeArray *)this)->next->ty]); } else - toDecoBuffer(&buf); + toDecoBuffer(&buf, true); len = buf.offset; name = (char *)alloca(19 + sizeof(len) * 3 + len + 1); buf.writeByte(0); @@ -1933,13 +1937,13 @@ return merge(); } -void TypeSArray::toDecoBuffer(OutBuffer *buf) +void TypeSArray::toDecoBuffer(OutBuffer *buf, bool mangle) { buf->writeByte(mangleChar[ty]); if (dim) buf->printf("%ju", dim->toInteger()); if (next) - next->toDecoBuffer(buf); + next->toDecoBuffer(buf, mangle); } void TypeSArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) @@ -2099,11 +2103,11 @@ return merge(); } -void TypeDArray::toDecoBuffer(OutBuffer *buf) +void TypeDArray::toDecoBuffer(OutBuffer *buf, bool mangle) { buf->writeByte(mangleChar[ty]); if (next) - next->toDecoBuffer(buf); + next->toDecoBuffer(buf, mangle); } void TypeDArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) @@ -2425,11 +2429,11 @@ return e; } -void TypeAArray::toDecoBuffer(OutBuffer *buf) +void TypeAArray::toDecoBuffer(OutBuffer *buf, bool mangle) { buf->writeByte(mangleChar[ty]); - index->toDecoBuffer(buf); - next->toDecoBuffer(buf); + index->toDecoBuffer(buf, mangle); + next->toDecoBuffer(buf, mangle); } void TypeAArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) @@ -2651,6 +2655,10 @@ this->varargs = varargs; this->linkage = linkage; this->inuse = 0; + +#if IN_LLVM + this->funcdecl = NULL; +#endif } Type *TypeFunction::syntaxCopy() @@ -2750,7 +2758,7 @@ return 2; } -void TypeFunction::toDecoBuffer(OutBuffer *buf) +void TypeFunction::toDecoBuffer(OutBuffer *buf, bool mangle) { unsigned char mc; //printf("TypeFunction::toDecoBuffer() this = %p %s\n", this, toChars()); @@ -2775,11 +2783,23 @@ assert(0); } buf->writeByte(mc); + + // LDC: if we're not producing a mangle string, add the this + // type to prevent merging different member function + if (!mangle && funcdecl) + { + if (AggregateDeclaration* ad = funcdecl->isMember()) + { + buf->writeByte('M'); + ad->type->toDecoBuffer(buf, false); + } + } + // Write argument types - Argument::argsToDecoBuffer(buf, parameters); + Argument::argsToDecoBuffer(buf, parameters, mangle); //if (buf->data[buf->offset - 1] == '@') halt(); buf->writeByte('Z' - varargs); // mark end of arg list - next->toDecoBuffer(buf); + next->toDecoBuffer(buf, mangle); inuse--; } @@ -3461,7 +3481,7 @@ return t; } -void TypeIdentifier::toDecoBuffer(OutBuffer *buf) +void TypeIdentifier::toDecoBuffer(OutBuffer *buf, bool mangle) { unsigned len; char *name; @@ -3915,7 +3935,7 @@ return sym->memtype->toBasetype(); } -void TypeEnum::toDecoBuffer(OutBuffer *buf) +void TypeEnum::toDecoBuffer(OutBuffer *buf, bool mangle) { char *name; name = sym->mangle(); @@ -4103,7 +4123,7 @@ return sym; } -void TypeTypedef::toDecoBuffer(OutBuffer *buf) +void TypeTypedef::toDecoBuffer(OutBuffer *buf, bool mangle) { unsigned len; char *name; @@ -4328,7 +4348,7 @@ return sym; } -void TypeStruct::toDecoBuffer(OutBuffer *buf) +void TypeStruct::toDecoBuffer(OutBuffer *buf, bool mangle) { unsigned len; char *name; @@ -4621,7 +4641,7 @@ return sym; } -void TypeClass::toDecoBuffer(OutBuffer *buf) +void TypeClass::toDecoBuffer(OutBuffer *buf, bool mangle) { unsigned len; char *name; @@ -5143,11 +5163,11 @@ Argument::argsToCBuffer(buf, hgs, arguments, 0); } -void TypeTuple::toDecoBuffer(OutBuffer *buf) +void TypeTuple::toDecoBuffer(OutBuffer *buf, bool mangle) { //printf("TypeTuple::toDecoBuffer() this = %p\n", this); OutBuffer buf2; - Argument::argsToDecoBuffer(&buf2, arguments); + Argument::argsToDecoBuffer(&buf2, arguments, mangle); unsigned len = buf2.offset; buf->printf("%c%d%.*s", mangleChar[ty], len, len, (char *)buf2.extractData()); } @@ -5409,7 +5429,7 @@ } -void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments) +void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments, bool mangle) { //printf("Argument::argsToDecoBuffer()\n"); @@ -5420,7 +5440,7 @@ for (size_t i = 0; i < dim; i++) { Argument *arg = Argument::getNth(arguments, i); - arg->toDecoBuffer(buf); + arg->toDecoBuffer(buf, mangle); } } } @@ -5454,7 +5474,7 @@ return NULL; } -void Argument::toDecoBuffer(OutBuffer *buf) +void Argument::toDecoBuffer(OutBuffer *buf, bool mangle) { switch (storageClass & (STCin | STCout | STCref | STClazy)) { case 0: @@ -5475,7 +5495,7 @@ #endif assert(0); } - type->toDecoBuffer(buf); + type->toDecoBuffer(buf, mangle); } /*************************************** diff -r 08f87d8cd101 -r 79758fd2f48a dmd/mtype.h --- a/dmd/mtype.h Mon Apr 13 17:42:36 2009 +0200 +++ b/dmd/mtype.h Wed Apr 15 20:06:25 2009 +0200 @@ -219,7 +219,8 @@ virtual d_uns64 size(Loc loc); virtual unsigned alignsize(); virtual Type *semantic(Loc loc, Scope *sc); - virtual void toDecoBuffer(OutBuffer *buf); + // append the mangleof or a string uniquely identifying this type to buf + virtual void toDecoBuffer(OutBuffer *buf, bool mangle); Type *merge(); virtual void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); virtual void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); @@ -336,7 +337,7 @@ unsigned alignsize(); Type *semantic(Loc loc, Scope *sc); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toDecoBuffer(OutBuffer *buf); + void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); int isString(); @@ -367,7 +368,7 @@ d_uns64 size(Loc loc); unsigned alignsize(); Type *semantic(Loc loc, Scope *sc); - void toDecoBuffer(OutBuffer *buf); + void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); int isString(); @@ -394,7 +395,7 @@ d_uns64 size(Loc loc); Type *semantic(Loc loc, Scope *sc); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toDecoBuffer(OutBuffer *buf); + void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); Expression *defaultInit(Loc loc); @@ -462,7 +463,7 @@ TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); - void toDecoBuffer(OutBuffer *buf); + void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); @@ -481,6 +482,8 @@ #elif IN_LLVM // LDC IrFuncTy fty; + + FuncDeclaration* funcdecl; #endif }; @@ -525,7 +528,7 @@ TypeIdentifier(Loc loc, Identifier *ident); Type *syntaxCopy(); //char *toChars(); - void toDecoBuffer(OutBuffer *buf); + void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); Dsymbol *toDsymbol(Scope *sc); @@ -544,7 +547,7 @@ TypeInstance(Loc loc, TemplateInstance *tempinst); Type *syntaxCopy(); //char *toChars(); - //void toDecoBuffer(OutBuffer *buf); + //void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); Type *semantic(Loc loc, Scope *sc); @@ -575,7 +578,7 @@ Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf); + void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); unsigned memalign(unsigned salign); @@ -610,7 +613,7 @@ Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf); + void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); Expression *getProperty(Loc loc, Identifier *ident); @@ -642,7 +645,7 @@ char *toChars(); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf); + void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); Expression *getProperty(Loc loc, Identifier *ident); @@ -682,7 +685,7 @@ Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf); + void toDecoBuffer(OutBuffer *buf, bool mangle); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); ClassDeclaration *isClassHandle(); @@ -714,7 +717,7 @@ int equals(Object *o); Type *reliesOnTident(); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void toDecoBuffer(OutBuffer *buf); + void toDecoBuffer(OutBuffer *buf, bool mangle); Expression *getProperty(Loc loc, Identifier *ident); TypeInfoDeclaration *getTypeInfoDeclaration(); }; @@ -746,11 +749,11 @@ Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg); Argument *syntaxCopy(); Type *isLazyArray(); - void toDecoBuffer(OutBuffer *buf); + void toDecoBuffer(OutBuffer *buf, bool mangle); static Arguments *arraySyntaxCopy(Arguments *args); static char *argsTypesToChars(Arguments *args, int varargs); static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs); - static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments); + static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments, bool mangle); static size_t dim(Arguments *arguments); static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL); }; diff -r 08f87d8cd101 -r 79758fd2f48a gen/arrays.h --- a/gen/arrays.h Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/arrays.h Wed Apr 15 20:06:25 2009 +0200 @@ -1,6 +1,8 @@ #ifndef LLVMC_GEN_ARRAYS_H #define LLVMC_GEN_ARRAYS_H +struct ArrayInitializer; + struct DSliceValue; const llvm::StructType* DtoArrayType(Type* arrayTy); diff -r 08f87d8cd101 -r 79758fd2f48a gen/classes.cpp --- a/gen/classes.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/classes.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -16,183 +16,10 @@ #include "gen/runtime.h" #include "gen/dvalue.h" #include "gen/nested.h" +#include "gen/utils.h" #include "ir/irstruct.h" - -////////////////////////////////////////////////////////////////////////////////////////// - -// adds the base interfaces of b and the given iri to IrStruct's interfaceMap -static void add_base_interfaces(IrStruct* to, IrInterface* iri, BaseClass* b) -{ - for (unsigned j = 0; j < b->baseInterfaces_dim; j++) - { - BaseClass *bc = &b->baseInterfaces[j]; - // add to map - if (to->interfaceMap.find(bc->base) == to->interfaceMap.end()) - { - to->interfaceMap.insert(std::make_pair(bc->base, iri)); - } - // add base interfaces - add_base_interfaces(to, iri, bc); - } -} - -// adds interface b to target, if newinstance != 0, then target must provide all -// functions required to implement b (it reimplements b) -static void add_interface(ClassDeclaration* target, BaseClass* b, int newinstance) -{ - Logger::println("adding interface: %s", b->base->toChars()); - LOG_SCOPE; - - InterfaceDeclaration* inter = b->base->isInterfaceDeclaration(); - DtoResolveClass(inter); - - assert(inter); - IrStruct* irstruct = target->ir.irStruct; - assert(irstruct); - - // add interface to map/list - // if it's already inserted in the map, it's because another interface has it as baseclass - // but if it appears here, it's because we're reimplementing it, so we overwrite the IrInterface entry - IrInterface* iri; - bool overwrite = false; - if (irstruct->interfaceMap.find(inter) != irstruct->interfaceMap.end()) - { - overwrite = true; - } - - iri = new IrInterface(b); - // add to map - if (overwrite) - irstruct->interfaceMap[b->base] = iri; - else - irstruct->interfaceMap.insert(std::make_pair(b->base, iri)); - - // add to ordered list - irstruct->interfaceVec.push_back(iri); - - // add to classinfo interfaces - if (newinstance) - irstruct->classInfoInterfaces.push_back(iri); - - // recursively assign this iri to all base interfaces - add_base_interfaces(irstruct, iri, b); - - // build the interface vtable - b->fillVtbl(target, &iri->vtblDecls, newinstance); - - // add the vtable type - assert(inter->type->ir.type); - irstruct->types.push_back( inter->type->ir.type->get() ); - // set and increment index - iri->index = irstruct->index++; -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void add_class_data(ClassDeclaration* target, ClassDeclaration* cd) -{ - Logger::println("Adding data from class: %s", cd->toChars()); - LOG_SCOPE; - - // recurse into baseClasses - if (cd->baseClass) - { - add_class_data(target, cd->baseClass); - //offset = baseClass->structsize; - } - - // add members - Array* arr = cd->members; - for (int k=0; k < arr->dim; k++) { - Dsymbol* s = (Dsymbol*)arr->data[k]; - s->codegen(Type::sir); - } - - // add interfaces - if (cd->vtblInterfaces) - { - Logger::println("num vtbl interfaces: %u", cd->vtblInterfaces->dim); - for (int i = 0; i < cd->vtblInterfaces->dim; i++) - { - BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i]; - assert(b); - // create new instances only for explicitly derived interfaces - add_interface(target, b, (cd == target)); - } - } -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void DtoDeclareInterface(InterfaceDeclaration* cd); -static void DtoConstInitInterface(InterfaceDeclaration* cd); -static void DtoDefineInterface(InterfaceDeclaration* cd); - -static void DtoResolveInterface(InterfaceDeclaration* cd) -{ - if (cd->ir.resolved) return; - cd->ir.resolved = true; - - Logger::println("DtoResolveInterface(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); - LOG_SCOPE; - - // get the TypeClass - assert(cd->type->ty == Tclass); - TypeClass* ts = (TypeClass*)cd->type; - - // create the IrStruct, we need somewhere to store the classInfo - assert(!cd->ir.irStruct); - IrStruct* irstruct = new IrStruct(cd); - cd->ir.irStruct = irstruct; - - // create the type - const LLType* t = LLArrayType::get(getVoidPtrType(), cd->vtbl.dim); - assert(!ts->ir.type); - ts->ir.type = new LLPATypeHolder(getPtrToType(t)); - - // ... and ClassInfo - std::string varname("_D"); - varname.append(cd->mangle()); - varname.append("11__InterfaceZ"); - - // create global - irstruct->classInfo = new llvm::GlobalVariable(irstruct->classInfoOpaque.get(), false, DtoLinkage(cd), NULL, varname, gIR->module); - - // handle base interfaces - if (cd->baseclasses.dim) - { - Logger::println("num baseclasses: %u", cd->baseclasses.dim); - LOG_SCOPE; - - for (int i=0; ibaseclasses.dim; i++) - { - BaseClass* bc = (BaseClass*)cd->baseclasses.data[i]; - Logger::println("baseclass %d: %s", i, bc->base->toChars()); - - InterfaceDeclaration* id = bc->base->isInterfaceDeclaration(); - assert(id); - - DtoResolveInterface(id); - - // add to interfaceInfos - IrInterface* iri = new IrInterface(bc); - irstruct->interfaceVec.push_back(iri); - irstruct->classInfoInterfaces.push_back(iri); - } - } - - // request declaration - DtoDeclareInterface(cd); - - // handle members - // like "nested" interfaces - Array* arr = cd->members; - for (int k=0; k < arr->dim; k++) { - Dsymbol* s = (Dsymbol*)arr->data[k]; - s->codegen(Type::sir); - } -} +#include "ir/irtypeclass.h" ////////////////////////////////////////////////////////////////////////////////////////// @@ -200,12 +27,6 @@ void DtoResolveClass(ClassDeclaration* cd) { - if (InterfaceDeclaration* id = cd->isInterfaceDeclaration()) - { - DtoResolveInterface(id); - return; - } - // make sure the base classes are processed first if (cd->baseClass) cd->baseClass->codegen(Type::sir); @@ -216,722 +37,61 @@ Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; - // get the TypeClass - assert(cd->type->ty == Tclass); - TypeClass* ts = (TypeClass*)cd->type; + // make sure type exists + DtoType(cd->type); - // create the IrStruct - assert(!cd->ir.irStruct); + // create IrStruct + assert(cd->ir.irStruct == NULL); IrStruct* irstruct = new IrStruct(cd); cd->ir.irStruct = irstruct; - // create the type - ts->ir.type = new LLPATypeHolder(llvm::OpaqueType::get()); - - // if it just a forward declaration? - if (cd->sizeok != 1) - { - // just name the type - gIR->module->addTypeName(cd->mangle(), ts->ir.type->get()); - return; - } - - // create the symbols we're going to need - // avoids chicken egg problems - llvm::GlobalValue::LinkageTypes _linkage = DtoLinkage(cd); - - // there is always a vtbl symbol - std::string varname("_D"); - varname.append(cd->mangle()); - varname.append("6__vtblZ"); - irstruct->vtbl = new llvm::GlobalVariable(irstruct->vtblInitTy.get(), true, _linkage, NULL, varname, gIR->module); - - // ... and initZ - varname = "_D"; - varname.append(cd->mangle()); - varname.append("6__initZ"); - irstruct->init = new llvm::GlobalVariable(irstruct->initOpaque.get(), true, _linkage, NULL, varname, gIR->module); - - // ... and ClassInfo - varname = "_D"; - varname.append(cd->mangle()); - varname.append("7__ClassZ"); - - // create global - irstruct->classInfo = new llvm::GlobalVariable(irstruct->classInfoOpaque.get(), false, _linkage, NULL, varname, gIR->module); - - // push state - gIR->structs.push_back(irstruct); - - // add vtable - irstruct->types.push_back(getPtrToType(irstruct->vtblTy.get())); - irstruct->index++; - - // add monitor - irstruct->types.push_back(getVoidPtrType()); - irstruct->index++; - - // add class data fields and interface vtables recursively - add_class_data(cd, cd); - - // check if errors occured while building interface vtables - if (global.errors) - fatal(); - - // create type - assert(irstruct->index == irstruct->types.size()); - const LLType* structtype = irstruct->build(); - - // refine abstract types for stuff like: class C {C next;} - llvm::PATypeHolder* spa = ts->ir.type; - llvm::cast(spa->get())->refineAbstractTypeTo(structtype); - structtype = isaStruct(spa->get()); - assert(structtype); - - // name the type - gIR->module->addTypeName(cd->mangle(), ts->ir.type->get()); - - // refine vtable type + bool needs_def = mustDefineSymbol(cd); - // void*[vtbl.dim] - llvm::cast(irstruct->vtblTy.get())->refineAbstractTypeTo(LLArrayType::get(getVoidPtrType(), cd->vtbl.dim)); - - // log -// if (Logger::enabled()) -// Logger::cout() << "final class type: " << *ts->ir.type->get() << '\n'; - - // pop state - gIR->structs.pop_back(); - - // queue declare - DtoDeclareClass(cd); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void DtoDeclareInterface(InterfaceDeclaration* cd) -{ - DtoResolveInterface(cd); - - if (cd->ir.declared) return; - cd->ir.declared = true; - - Logger::println("DtoDeclareInterface(%s): %s", cd->toPrettyChars(), cd->locToChars()); - LOG_SCOPE; - - assert(cd->ir.irStruct); - IrStruct* irstruct = cd->ir.irStruct; - - // get interface info type - const llvm::StructType* infoTy = DtoInterfaceInfoType(); + // emit the ClassZ symbol + LLGlobalVariable* ClassZ = irstruct->getClassInfoSymbol(); - // interface info array - if (!irstruct->interfaceVec.empty()) { - // symbol name - std::string nam = "_D"; - nam.append(cd->mangle()); - nam.append("16__interfaceInfosZ"); - - llvm::GlobalValue::LinkageTypes linkage = DtoLinkage(cd); - - // resolve array type - const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, irstruct->interfaceVec.size()); - // declare global - irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, linkage, NULL, nam, gIR->module); - - // do each interface info - unsigned idx = 0; - size_t n = irstruct->interfaceVec.size(); - for (size_t i=0; i < n; i++) - { - IrInterface* iri = irstruct->interfaceVec[i]; - ClassDeclaration* id = iri->decl; - - // always create interfaceinfos - LLConstant* idxs[2] = {DtoConstUint(0), DtoConstUint(idx)}; - iri->info = llvm::ConstantExpr::getGetElementPtr(irstruct->interfaceInfos, idxs, 2); - idx++; - } - } - - // declare the classinfo - DtoDeclareClassInfo(cd); - - // request const init - DtoConstInitInterface(cd); - - // emit typeinfo and request definition - if (mustDefineSymbol(cd)) + // interface only emit typeinfo and classinfo + if (!cd->isInterfaceDeclaration()) { - DtoDefineInterface(cd); - DtoTypeInfoOf(cd->type, false); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// - -// FIXME: this needs to be cleaned up - -void DtoDeclareClass(ClassDeclaration* cd) -{ - if (InterfaceDeclaration* id = cd->isInterfaceDeclaration()) - { - DtoDeclareInterface(id); - return; - } - - DtoResolveClass(cd); - - if (cd->ir.declared) return; - cd->ir.declared = true; - - Logger::println("DtoDeclareClass(%s): %s", cd->toPrettyChars(), cd->locToChars()); - LOG_SCOPE; - - //printf("declare class: %s\n", cd->toPrettyChars()); - - assert(cd->type->ty == Tclass); - TypeClass* ts = (TypeClass*)cd->type; - - assert(cd->ir.irStruct); - IrStruct* irstruct = cd->ir.irStruct; + // emit the initZ symbol + LLGlobalVariable* initZ = irstruct->getInitSymbol(); + // emit the vtblZ symbol + LLGlobalVariable* vtblZ = irstruct->getVtblSymbol(); - gIR->structs.push_back(irstruct); - - bool needs_definition = false; - if (mustDefineSymbol(cd)) { - needs_definition = true; - } - - llvm::GlobalValue::LinkageTypes _linkage = DtoLinkage(cd); - - // get interface info type - const llvm::StructType* infoTy = DtoInterfaceInfoType(); - - // interface info array - if (!irstruct->interfaceVec.empty()) { - // symbol name - std::string nam = "_D"; - nam.append(cd->mangle()); - nam.append("16__interfaceInfosZ"); - // resolve array type - const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, irstruct->interfaceVec.size()); - // declare global - irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, _linkage, NULL, nam, gIR->module); - } - - // DMD gives abstract classes a full ClassInfo, so we do it as well - - // interface vtables - unsigned idx = 0; - for (IrStruct::InterfaceVectorIter i=irstruct->interfaceVec.begin(); i!=irstruct->interfaceVec.end(); ++i) - { - IrInterface* iri = *i; - ClassDeclaration* id = iri->decl; + // emit the interfaceInfosZ symbol if necessary + if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) + getInterfaceArraySymbol(); // initializer is applied when it's built - std::string nam("_D"); - nam.append(cd->mangle()); - nam.append("11__interface"); - nam.append(id->mangle()); - nam.append("6__vtblZ"); - - iri->vtbl = new llvm::GlobalVariable(iri->vtblInitTy.get(), true, _linkage, 0, nam, gIR->module); - - // always set the interface info as it's need as the first vtbl entry - LLConstant* idxs[2] = {DtoConstUint(0), DtoConstUint(idx)}; - iri->info = llvm::ConstantExpr::getGetElementPtr(irstruct->interfaceInfos, idxs, 2); - idx++; - } - - gIR->structs.pop_back(); - - // request const init - DtoConstInitClass(cd); - - // define ? (set initializers) - if (needs_definition) - DtoDefineClass(cd); - - // classinfo - DtoDeclareClassInfo(cd); - - // do typeinfo ? - if (needs_definition) - DtoTypeInfoOf(cd->type, false); -} - -////////////////////////////////////////////////////////////////////////////// + // perform definition + if (needs_def) + { + // set symbol initializers + initZ->setInitializer(irstruct->getDefaultInit()); + vtblZ->setInitializer(irstruct->getVtblInit()); + } -// adds data fields and interface vtables to the constant initializer of class cd -static size_t init_class_initializer(std::vector& inits, ClassDeclaration* target, ClassDeclaration* cd, size_t offsetbegin) -{ - // first do baseclasses - if (cd->baseClass) - { - offsetbegin = init_class_initializer(inits, target, cd->baseClass, offsetbegin); - } - - Logger::println("adding data of %s to %s starting at %lu", cd->toChars(), target->toChars(), offsetbegin); - LOG_SCOPE; - - // add default fields - VarDeclaration** fields = (VarDeclaration**)cd->fields.data; - size_t nfields = cd->fields.dim; - - std::vector defVars; - defVars.reserve(nfields); - - size_t lastoffset = offsetbegin; - size_t lastsize = 0; - - // find fields that contribute to default - for (size_t i=0; ioffset; - size_t size = var->type->size(); - if (offset >= lastoffset+lastsize) + // emit members + if (cd->members) { - Logger::println(" added %s", var->toChars()); - lastoffset = offset; - lastsize = size; - defVars.push_back(var); - } - else - { - Logger::println(" skipped %s at offset %u, current pos is %lu", var->toChars(), var->offset, lastoffset+lastsize); + ArrayIter it(*cd->members); + while (!it.done()) + { + Dsymbol* member = it.get(); + if (member) + member->codegen(Type::sir); + it.next(); + } } } - // reset offsets, we're going from beginning again - lastoffset = offsetbegin; - lastsize = 0; - - // go through the default vars and build the default constant initializer - // adding zeros along the way to live up to alignment expectations - size_t nvars = defVars.size(); - for (size_t i=0; itype->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset); - - // get offset and size - size_t offset = var->offset; - size_t size = var->type->size(); - - // is there space in between last last offset and this one? - // if so, fill it with zeros - if (offset > lastoffset+lastsize) - { - size_t pos = lastoffset + lastsize; - addZeros(inits, pos, offset); - } - - // add the field - // and build its constant initializer lazily - if (!var->ir.irField->constInit) - var->ir.irField->constInit = DtoConstInitializer(var->loc, var->type, var->init); - inits.push_back(var->ir.irField->constInit); - - lastoffset = offset; - lastsize = var->type->size(); - } - - // if it's a class, and it implements interfaces, add the vtables - as found in the target class! - IrStruct* irstruct = target->ir.irStruct; - - size_t nvtbls = cd->vtblInterfaces->dim; - for(size_t i=0; ivtblInterfaces->data[i]; - IrStruct::InterfaceMap::iterator iter = irstruct->interfaceMap.find(bc->base); - assert(iter != irstruct->interfaceMap.end()); - - IrInterface* iri = iter->second; - if (iri->vtbl) - inits.push_back(iri->vtbl); - else // abstract impl - inits.push_back(getNullPtr(getVoidPtrType())); - - lastoffset += lastsize; - lastsize = PTRSIZE; - } - - // return next offset - return lastoffset + lastsize; -} - -////////////////////////////////////////////////////////////////////////////// - -// build the vtable initializer for class cd -static void init_class_vtbl_initializer(ClassDeclaration* cd) -{ - cd->codegen(Type::sir); - - // generate vtable initializer - std::vector sinits(cd->vtbl.dim, NULL); - - IrStruct* irstruct = cd->ir.irStruct; - - assert(cd->vtbl.dim > 1); - - DtoDeclareClassInfo(cd); - - // first entry always classinfo - assert(irstruct->classInfo); - sinits[0] = DtoBitCast(irstruct->classInfo, DtoType(ClassDeclaration::classinfo->type)); - - // add virtual functions - for (int k=1; k < cd->vtbl.dim; k++) - { - Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[k]; - assert(dsym); - -// Logger::println("vtbl[%d] = %s", k, dsym->toChars()); - - FuncDeclaration* fd = dsym->isFuncDeclaration(); - assert(fd); - - // if function is abstract, - // or class is abstract, and func has no body, - // emit a null vtbl entry - if (fd->isAbstract() || (cd->isAbstract() && !fd->fbody)) - { - sinits[k] = getNullPtr(getVoidPtrType()); - } - else - { - fd->codegen(Type::sir); - Logger::println("F = %s", fd->toPrettyChars()); - assert(fd->ir.irFunc); - assert(fd->ir.irFunc->func); - sinits[k] = fd->ir.irFunc->func; - } - -// if (Logger::enabled()) -// Logger::cout() << "vtbl[" << k << "] = " << *sinits[k] << std::endl; - } - - irstruct->constVtbl = LLConstantStruct::get(sinits); - - // refine type - llvm::cast(irstruct->vtblInitTy.get())->refineAbstractTypeTo(irstruct->constVtbl->getType()); - -// if (Logger::enabled()) -// Logger::cout() << "vtbl initializer: " << *irstruct->constVtbl << std::endl; -} - -////////////////////////////////////////////////////////////////////////////// - -static void init_class_interface_vtbl_initializers(ClassDeclaration* cd) -{ - IrStruct* irstruct = cd->ir.irStruct; - - // don't do anything if list is empty - if (irstruct->interfaceVec.empty()) - return; - - std::vector inits; - std::vector infoInits(3); - - // go through each interface - size_t ninter = irstruct->interfaceVec.size(); - for (size_t i=0; iinterfaceVec[i]; - Logger::println("interface %s", iri->decl->toChars()); - - // build vtable intializer for this interface implementation - Array& arr = iri->vtblDecls; - size_t narr = arr.dim; - - if (narr > 0) - { - inits.resize(narr, NULL); - - // first is always the interface info - assert(iri->info); - inits[0] = iri->info; - - // build vtable - for (size_t j=1; j < narr; j++) - { - Dsymbol* dsym = (Dsymbol*)arr.data[j]; - if (!dsym) - { - inits[j] = getNullPtr(getVoidPtrType()); - continue; - } - - //Logger::println("ivtbl[%d] = %s", j, dsym->toChars()); - - // must all be functions - FuncDeclaration* fd = dsym->isFuncDeclaration(); - assert(fd); - - if (fd->isAbstract()) - inits[j] = getNullPtr(getVoidPtrType()); - else - { - fd->codegen(Type::sir); - - assert(fd->ir.irFunc->func); - inits[j] = fd->ir.irFunc->func; - } - - //if (Logger::enabled()) - // Logger::cout() << "ivtbl[" << j << "] = " << *inits[j] << std::endl; - } - - // build the constant - iri->vtblInit = LLConstantStruct::get(inits); - } - - // build the interface info for ClassInfo - // generate interface info initializer - - iri->decl->codegen(Type::sir); - - // classinfo - IrStruct* iris = iri->decl->ir.irStruct; - assert(iris); - assert(iris->classInfo); - infoInits[0] = DtoBitCast(iris->classInfo, DtoType(ClassDeclaration::classinfo->type)); - - // vtbl - LLConstant* c; - if (iri->vtbl) - c = llvm::ConstantExpr::getBitCast(iri->vtbl, getPtrToType(getVoidPtrType())); - else - c = getNullPtr(getPtrToType(getVoidPtrType())); - infoInits[1] = DtoConstSlice(DtoConstSize_t(narr), c); - - // offset - size_t ioff; - if (iri->index == 0) - ioff = 0; - else - ioff = gTargetData->getStructLayout(isaStruct(cd->type->ir.type->get()))->getElementOffset(iri->index); + // emit typeinfo + DtoTypeInfoOf(cd->type); - Logger::println("DMD interface offset: %d, LLVM interface offset: %lu", iri->base->offset, ioff); - assert(iri->base->offset == ioff); - infoInits[2] = DtoConstUint(ioff); - - // create interface info initializer constant - iri->infoInit = llvm::cast(llvm::ConstantStruct::get(infoInits)); - } -} - -////////////////////////////////////////////////////////////////////////////// - -static void DtoConstInitInterface(InterfaceDeclaration* cd) -{ - DtoDeclareInterface(cd); - - if (cd->ir.initialized) return; - cd->ir.initialized = true; - - Logger::println("DtoConstInitClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); - LOG_SCOPE; - - init_class_interface_vtbl_initializers(cd); -} - -////////////////////////////////////////////////////////////////////////////// - -void DtoConstInitClass(ClassDeclaration* cd) -{ - if (InterfaceDeclaration* it = cd->isInterfaceDeclaration()) + // define classinfo + if (needs_def) { - DtoConstInitInterface(it); - return; - } - - DtoDeclareClass(cd); - - if (cd->ir.initialized) return; - cd->ir.initialized = true; - - Logger::println("DtoConstInitClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); - LOG_SCOPE; - - // get IrStruct - IrStruct* irstruct = cd->ir.irStruct; - gIR->structs.push_back(irstruct); - - // get types - TypeClass* tc = (TypeClass*)cd->type; - const llvm::StructType* structtype = isaStruct(tc->ir.type->get()); - assert(structtype); - const llvm::ArrayType* vtbltype = isaArray(irstruct->vtblTy.get()); - assert(vtbltype); - - // build initializer list - std::vector inits; - inits.reserve(irstruct->varDecls.size()); - - // vtable is always first - assert(irstruct->vtbl != 0); - inits.push_back(irstruct->vtbl); - - // then comes monitor - inits.push_back(LLConstant::getNullValue(getVoidPtrType())); - - // recursively do data and interface vtables - init_class_initializer(inits, cd, cd, 2 * PTRSIZE); - - // build vtable initializer - init_class_vtbl_initializer(cd); - - // build interface vtables - init_class_interface_vtbl_initializers(cd); - - // build constant from inits - assert(!irstruct->constInit); - irstruct->constInit = LLConstantStruct::get(inits); // classes are never packed - - // refine __initZ global type to the one of the initializer - llvm::cast(irstruct->initOpaque.get())->refineAbstractTypeTo(irstruct->constInit->getType()); - - // build initializers for static member variables - size_t n = irstruct->staticVars.size(); - for (size_t i = 0; i < n; ++i) - { - DtoConstInitGlobal(irstruct->staticVars[i]); + ClassZ->setInitializer(irstruct->getClassInfoInit()); } - // This is all we use it for. Clear the memory! - irstruct->staticVars.clear(); - -// if (Logger::enabled()) -// { -// Logger::cout() << "class " << cd->toChars() << std::endl; -// Logger::cout() << "type " << *cd->type->ir.type->get() << std::endl; -// Logger::cout() << "initializer " << *irstruct->constInit << std::endl; -// } - - gIR->structs.pop_back(); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void DefineInterfaceInfos(IrStruct* irstruct) -{ - // always do interface info array when possible - std::vector infoInits; - - size_t n = irstruct->interfaceVec.size(); - infoInits.reserve(n); - - for (size_t i=0; i < n; i++) - { - IrInterface* iri = irstruct->interfaceVec[i]; - assert(iri->infoInit); - infoInits.push_back(iri->infoInit); - } - - // set initializer - if (!infoInits.empty()) - { - const LLArrayType* arrty = LLArrayType::get(infoInits[0]->getType(), infoInits.size()); - LLConstant* arrInit = llvm::ConstantArray::get(arrty, infoInits); - irstruct->interfaceInfos->setInitializer(arrInit); - } - else - { - assert(irstruct->interfaceInfos == NULL); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void DtoDefineInterface(InterfaceDeclaration* cd) -{ - DtoConstInitInterface(cd); - - if (cd->ir.defined) return; - cd->ir.defined = true; - - Logger::println("DtoDefineClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); - LOG_SCOPE; - - // defined interface infos - DefineInterfaceInfos(cd->ir.irStruct); - - // define the classinfo - if (mustDefineSymbol(cd)) - { - DtoDefineClassInfo(cd); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// - -// FIXME: clean this up - -void DtoDefineClass(ClassDeclaration* cd) -{ - if (InterfaceDeclaration* id = cd->isInterfaceDeclaration()) - { - DtoDefineInterface(id); - return; - } - - DtoConstInitClass(cd); - - if (cd->ir.defined) return; - cd->ir.defined = true; - - Logger::println("DtoDefineClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); - LOG_SCOPE; - - // get the struct (class) type - assert(cd->type->ty == Tclass); - TypeClass* ts = (TypeClass*)cd->type; - - IrStruct* irstruct = cd->ir.irStruct; - - assert(mustDefineSymbol(cd)); - - // sanity check - assert(irstruct->init); - assert(irstruct->constInit); - assert(irstruct->vtbl); - assert(irstruct->constVtbl); - -// if (Logger::enabled()) -// { -// Logger::cout() << "initZ: " << *irstruct->init << std::endl; -// Logger::cout() << "cinitZ: " << *irstruct->constInit << std::endl; -// Logger::cout() << "vtblZ: " << *irstruct->vtbl << std::endl; -// Logger::cout() << "cvtblZ: " << *irstruct->constVtbl << std::endl; -// } - - // set initializers - irstruct->init->setInitializer(irstruct->constInit); - irstruct->vtbl->setInitializer(irstruct->constVtbl); - - // initialize interface vtables - size_t n = irstruct->interfaceVec.size(); - for (size_t i=0; iinterfaceVec[i]; - Logger::println("interface %s", iri->base->base->toChars()); - assert(iri->vtblInit); - - // refine the init type - llvm::cast(iri->vtblInitTy.get())->refineAbstractTypeTo(iri->vtblInit->getType()); - - // apply initializer - assert(iri->vtbl); - iri->vtbl->setInitializer(iri->vtblInit); - } - - DefineInterfaceInfos(irstruct); - - // generate classinfo - DtoDefineClassInfo(cd); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -959,7 +119,7 @@ else { llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_allocclass"); - LLConstant* ci = DtoBitCast(tc->sym->ir.irStruct->classInfo, DtoType(ClassDeclaration::classinfo->type)); + LLConstant* ci = DtoBitCast(tc->sym->ir.irStruct->getClassInfoSymbol(), DtoType(ClassDeclaration::classinfo->type)); mem = gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc").getInstruction(); mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc"); } @@ -1019,9 +179,8 @@ uint64_t n = getTypePaddedSize(tc->ir.type->get()) - presz; // set vtable field seperately, this might give better optimization - assert(tc->sym->ir.irStruct->vtbl); LLValue* tmp = DtoGEPi(dst,0,0,"vtbl"); - LLValue* val = DtoBitCast(tc->sym->ir.irStruct->vtbl, tmp->getType()->getContainedType(0)); + LLValue* val = DtoBitCast(tc->sym->ir.irStruct->getVtblSymbol(), tmp->getType()->getContainedType(0)); DtoStore(val, tmp); // monitor always defaults to zero @@ -1034,10 +193,8 @@ return; // copy the rest from the static initializer - assert(tc->sym->ir.irStruct->init); - LLValue* dstarr = DtoGEPi(dst,0,2,"tmp"); - LLValue* srcarr = DtoGEPi(tc->sym->ir.irStruct->init,0,2,"tmp"); + LLValue* srcarr = DtoGEPi(tc->sym->ir.irStruct->getInitSymbol(),0,2,"tmp"); DtoMemCpy(dstarr, srcarr, DtoConstSize_t(n)); } @@ -1098,18 +255,22 @@ // class -> interface - static cast else if (it->isBaseOf(fc->sym,NULL)) { Logger::println("static down cast"); + // get the from class ClassDeclaration* cd = fc->sym->isClassDeclaration(); DtoResolveClass(cd); // add this IrStruct* irstruct = cd->ir.irStruct; + IrTypeClass* typeclass = fc->irtype->isClass(); + // find interface impl - IrStruct::InterfaceMapIter iriter = irstruct->interfaceMap.find(it); - assert(iriter != irstruct->interfaceMap.end()); - IrInterface* iri = iriter->second; + + size_t i_index = typeclass->getInterfaceIndex(it); + assert(i_index != ~0 && "requesting interface that is not implemented by this class"); + // offset pointer LLValue* v = val->getRVal(); LLValue* orig = v; - v = DtoGEPi(v, 0, iri->index); + v = DtoGEPi(v, 0, i_index); const LLType* ifType = DtoType(_to); if (Logger::enabled()) { @@ -1117,12 +278,14 @@ Logger::cout() << "T = " << *ifType << std::endl; } v = DtoBitCast(v, ifType); + // Check whether the original value was null, and return null if so. // Sure we could have jumped over the code above in this case, but // it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it // should be pretty cheap and perfectly safe even if the original was null. LLValue* isNull = gIR->ir->CreateICmpEQ(orig, LLConstant::getNullValue(orig->getType()), ".nullcheck"); v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(ifType), v, ".interface"); + // return r-value return new DImValue(_to, v); } @@ -1179,8 +342,8 @@ // ClassInfo c TypeClass* to = (TypeClass*)_to->toBasetype(); to->sym->codegen(Type::sir); - assert(to->sym->ir.irStruct->classInfo); - LLValue* cinfo = to->sym->ir.irStruct->classInfo; + + LLValue* cinfo = to->sym->ir.irStruct->getClassInfoSymbol(); // unfortunately this is needed as the implementation of object differs somehow from the declaration // this could happen in user code as well :/ cinfo = DtoBitCast(cinfo, funcTy->getParamType(1)); @@ -1243,8 +406,7 @@ // ClassInfo c TypeClass* to = (TypeClass*)_to->toBasetype(); to->sym->codegen(Type::sir); - assert(to->sym->ir.irStruct->classInfo); - LLValue* cinfo = to->sym->ir.irStruct->classInfo; + LLValue* cinfo = to->sym->ir.irStruct->getClassInfoSymbol(); // unfortunately this is needed as the implementation of object differs somehow from the declaration // this could happen in user code as well :/ cinfo = DtoBitCast(cinfo, funcTy->getParamType(1)); @@ -1346,23 +508,6 @@ ////////////////////////////////////////////////////////////////////////////////////////// -void DtoDeclareClassInfo(ClassDeclaration* cd) -{ - IrStruct* irstruct = cd->ir.irStruct; - - if (irstruct->classInfoDeclared) return; - irstruct->classInfoDeclared = true; - - Logger::println("DtoDeclareClassInfo(%s)", cd->toChars()); - LOG_SCOPE; - - // resovle ClassInfo - ClassDeclaration* cinfo = ClassDeclaration::classinfo; - DtoResolveClass(cinfo); -} - -////////////////////////////////////////////////////////////////////////////////////////// - #if GENERATE_OFFTI // build a single element for the OffsetInfo[] of ClassInfo @@ -1467,7 +612,7 @@ return flags; } -void DtoDefineClassInfo(ClassDeclaration* cd) +LLConstant* DtoDefineClassInfo(ClassDeclaration* cd) { // The layout is: // { @@ -1486,25 +631,14 @@ // void *defaultConstructor; // } - IrStruct* ir = cd->ir.irStruct; - - if (ir->classInfoDefined) return; - ir->classInfoDefined = true; - Logger::println("DtoDefineClassInfo(%s)", cd->toChars()); LOG_SCOPE; + IrStruct* ir = cd->ir.irStruct; + assert(cd->type->ty == Tclass); - assert(ir->classInfo); TypeClass* cdty = (TypeClass*)cd->type; - if (!cd->isInterfaceDeclaration()) - { - assert(ir->init); - assert(ir->constInit); - assert(ir->vtbl); - assert(ir->constVtbl); - } // holds the list of initializers for llvm std::vector inits; @@ -1518,8 +652,7 @@ const LLType* voidPtrPtr = getPtrToType(voidPtr); // own vtable - c = cinfo->ir.irStruct->vtbl; - assert(c); + c = cinfo->ir.irStruct->getVtblSymbol(); inits.push_back(c); // monitor @@ -1531,9 +664,9 @@ c = DtoConstSlice(DtoConstSize_t(0), LLConstant::getNullValue(voidPtr)); else { - c = DtoBitCast(ir->init, voidPtr); + c = DtoBitCast(ir->getInitSymbol(), voidPtr); //Logger::cout() << *ir->constInit->getType() << std::endl; - size_t initsz = getTypePaddedSize(ir->init->getType()->getContainedType(0)); + size_t initsz = getTypePaddedSize(ir->getInitSymbol()->getType()->getContainedType(0)); c = DtoConstSlice(DtoConstSize_t(initsz), c); } inits.push_back(c); @@ -1554,36 +687,19 @@ if (cd->isInterfaceDeclaration()) c = DtoConstSlice(DtoConstSize_t(0), LLConstant::getNullValue(getPtrToType(voidPtr))); else { - c = DtoBitCast(ir->vtbl, voidPtrPtr); + c = DtoBitCast(ir->getVtblSymbol(), voidPtrPtr); c = DtoConstSlice(DtoConstSize_t(cd->vtbl.dim), c); } inits.push_back(c); // interfaces array - VarDeclaration* intersVar = (VarDeclaration*)cinfo->fields.data[3]; - const LLType* intersTy = DtoType(intersVar->type); - if (!ir->interfaceInfos) - c = LLConstant::getNullValue(intersTy); - else { - const LLType* t = intersTy->getContainedType(1); // .ptr - // cast to Interface* - c = DtoBitCast(ir->interfaceInfos, t); - size_t isz = ir->interfaceVec.size(); - size_t iisz = ir->classInfoInterfaces.size(); - assert(iisz <= isz); - // offset - we only want the 'iisz' last ones - LLConstant* idx = DtoConstUint(isz - iisz); - c = llvm::ConstantExpr::getGetElementPtr(c, &idx, 1); - // make array - c = DtoConstSlice(DtoConstSize_t(iisz), c); - } + c = ir->getClassInfoInterfaces(); inits.push_back(c); // base classinfo // interfaces never get a base , just the interfaces[] if (cd->baseClass && !cd->isInterfaceDeclaration()) { - DtoDeclareClassInfo(cd->baseClass); - c = cd->baseClass->ir.irStruct->classInfo; + c = cd->baseClass->ir.irStruct->getClassInfoSymbol(); assert(c); inits.push_back(c); } @@ -1684,9 +800,11 @@ //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n'; ir->constClassInfo = finalinit; - // refine the type - llvm::cast(ir->classInfoOpaque.get())->refineAbstractTypeTo(finalinit->getType()); + // sanity check + assert(finalinit->getType() == ir->classInfo->getType()->getContainedType(0) && + "__ClassZ initializer does not match the ClassInfo type"); + - // apply initializer - ir->classInfo->setInitializer(finalinit); + // return initializer + return finalinit; } diff -r 08f87d8cd101 -r 79758fd2f48a gen/classes.h --- a/gen/classes.h Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/classes.h Wed Apr 15 20:06:25 2009 +0200 @@ -3,28 +3,21 @@ #include "gen/structs.h" -/** - * Resolves the llvm type for a class declaration - */ +/// Resolves the llvm type for a class declaration void DtoResolveClass(ClassDeclaration* cd); -/** - * Provides the llvm declaration for a class declaration - */ +/// Provides the llvm declaration for a class declaration void DtoDeclareClass(ClassDeclaration* cd); -/** - * Constructs the constant initializer for a class declaration - */ +/// Constructs the constant initializer for a class declaration void DtoConstInitClass(ClassDeclaration* cd); -/** - * Provides the llvm definition for a class declaration - */ +/// Provides the llvm definition for a class declaration void DtoDefineClass(ClassDeclaration* cd); -void DtoDeclareClassInfo(ClassDeclaration* cd); -void DtoDefineClassInfo(ClassDeclaration* cd); +/// Builds the initializer of cd's ClassInfo. +/// FIXME: this should be put into IrStruct and eventually IrClass. +LLConstant* DtoDefineClassInfo(ClassDeclaration* cd); DValue* DtoNewClass(Loc loc, TypeClass* type, NewExp* newexp); void DtoInitClass(TypeClass* tc, LLValue* dst); diff -r 08f87d8cd101 -r 79758fd2f48a gen/declarations.cpp --- a/gen/declarations.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/declarations.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -14,6 +14,8 @@ #include "ir/ir.h" #include "ir/irvar.h" +#include "ir/irtype.h" +#include "ir/irtypestruct.h" /* ================================================================== */ @@ -72,11 +74,14 @@ /* ================================================================== */ +// FIXME: this is horrible!!! + void VarDeclaration::codegen(Ir* p) { Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; + // just forward aliases if (aliassym) { Logger::println("alias sym"); @@ -84,10 +89,11 @@ return; } + // output the parent aggregate first if (AggregateDeclaration* ad = isMember()) ad->codegen(p); - // global variable or magic + // global variable #if DMDV2 // taken from dmd2/structs if (isDataseg() || (storage_class & (STCconst | STCinvariant) && init)) @@ -138,25 +144,8 @@ if (nakedUse) gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType())); - // don't initialize static struct members yet, they might be of the struct type - // which doesn't have a static initializer yet. - if (AggregateDeclaration* ad = isMember()) - ad->ir.irStruct->staticVars.push_back(this); - else - DtoConstInitGlobal(this); - } - else - { - // might already have its irField, as classes derive each other without getting copies of the VarDeclaration - if (!ir.irField) - { - assert(!ir.isSet()); - ir.irField = new IrField(this); - } - IrStruct* irstruct = gIR->topstruct(); - irstruct->addVar(this); - - Logger::println("added offset %u", offset); + // initialize + DtoConstInitGlobal(this); } } @@ -164,8 +153,7 @@ void TypedefDeclaration::codegen(Ir*) { - static int tdi = 0; - Logger::print("TypedefDeclaration::toObjFile(%d): %s\n", tdi++, toChars()); + Logger::print("TypedefDeclaration::toObjFile: %s\n", toChars()); LOG_SCOPE; // generate typeinfo @@ -181,33 +169,12 @@ /* ================================================================== */ -void FuncDeclaration::codegen(Ir*) +void FuncDeclaration::codegen(Ir* p) { - DtoResolveDsymbol(this); -} - -/* ================================================================== */ - -void AnonDeclaration::codegen(Ir* p) -{ - Array *d = include(NULL, NULL); - - if (d) + // don't touch function aliases, they don't contribute any new symbols + if (!isFuncAliasDeclaration()) { - // get real aggregate parent - IrStruct* irstruct = gIR->topstruct(); - - // push a block on the stack - irstruct->pushAnon(isunion); - - // go over children - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->codegen(p); - } - - // finish - irstruct->popAnon(); + DtoResolveDsymbol(this); } } diff -r 08f87d8cd101 -r 79758fd2f48a gen/functions.cpp --- a/gen/functions.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/functions.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -201,7 +201,9 @@ llvm::FunctionType* functype = llvm::FunctionType::get(f->fty.ret->ltype, argtypes, f->fty.c_vararg); f->ir.type = new llvm::PATypeHolder(functype); +#if 0 Logger::cout() << "Final function type: " << *functype << "\n"; +#endif return functype; } @@ -304,16 +306,6 @@ return; // ignore declaration completely } - if (AggregateDeclaration* ad = fdecl->isMember()) - { - ad->codegen(Type::sir); - if (ad->isStructDeclaration() && llvm::isa(DtoType(ad->type))) - { - ad->ir.irStruct->structFuncs.push_back(fdecl); - return; - } - } - //printf("resolve function: %s\n", fdecl->toPrettyChars()); if (fdecl->parent) @@ -372,7 +364,6 @@ // queue declaration unless the function is abstract without body if (!fdecl->isAbstract() || fdecl->fbody) { - Logger::println("Ignoring declaration of abstract bodyless function %s", fdecl->toPrettyChars()); DtoDeclareFunction(fdecl); } } @@ -465,6 +456,9 @@ Type* t = fdecl->type->toBasetype(); TypeFunction* f = (TypeFunction*)t; + // sanity check + assert(fdecl == f->funcdecl && "the function type does not point to this function"); + bool declareOnly = !mustDefineSymbol(fdecl); if (fdecl->llvmInternal == LLVMva_start) diff -r 08f87d8cd101 -r 79758fd2f48a gen/llvmhelpers.cpp --- a/gen/llvmhelpers.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/llvmhelpers.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -1069,7 +1069,8 @@ else if (StructInitializer* si = init->isStructInitializer()) { Logger::println("const struct initializer"); - _init = DtoConstStructInitializer(si); + si->ad->codegen(Type::sir); + return si->ad->ir.irStruct->createStructInitializer(si); } else if (ArrayInitializer* ai = init->isArrayInitializer()) { diff -r 08f87d8cd101 -r 79758fd2f48a gen/logger.h --- a/gen/logger.h Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/logger.h Wed Apr 15 20:06:25 2009 +0200 @@ -33,5 +33,7 @@ #define LOG_SCOPE Logger::LoggerScope _logscope; +#define IF_LOG if (Logger::enabled()) + #endif diff -r 08f87d8cd101 -r 79758fd2f48a gen/structs.cpp --- a/gen/structs.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/structs.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -15,438 +15,10 @@ #include "gen/structs.h" #include "gen/dvalue.h" #include "gen/functions.h" +#include "gen/utils.h" #include "ir/irstruct.h" - -////////////////////////////////////////////////////////////////////////////////////////// - -// pair of var and its init -typedef std::pair VarInitPair; - -// comparison func for qsort -static int varinit_offset_cmp_func(const void* p1, const void* p2) -{ - VarDeclaration* v1 = ((VarInitPair*)p1)->first; - VarDeclaration* v2 = ((VarInitPair*)p2)->first; - if (v1->offset < v2->offset) - return -1; - else if (v1->offset > v2->offset) - return 1; - else - return 0; -} - -/* -this uses a simple algorithm to build the correct constant - -(1) first sort the explicit initializers by offset... well, DMD doesn't :) - -(2) if there is NO space before the next explicit initializeer, goto (9) -(3) find the next default initializer that fits before it, if NOT found goto (7) -(4) insert zero padding up to the next default initializer -(5) insert the next default initializer -(6) goto (2) - -(7) insert zero padding up to the next explicit initializer - -(9) insert the next explicit initializer -(10) goto (2) - -(11) done - -(next can be the end too) - -*/ - -// return the next default initializer to use or null -static VarDeclaration* nextDefault(IrStruct* irstruct, size_t& idx, size_t pos, size_t offset) -{ - IrStruct::VarDeclVector& defaults = irstruct->defVars; - size_t ndefaults = defaults.size(); - - // for each valid index - while(idx < ndefaults) - { - VarDeclaration* v = defaults[idx]; - - // skip defaults before pos - if (v->offset < pos) - { - idx++; - continue; - } - - // this var default fits - if (v->offset >= pos && v->offset + v->type->size() <= offset) - return v; - - // not usable - break; - } - - // not usable - return NULL; -} - -LLConstant* DtoConstStructInitializer(StructInitializer* si) -{ - Logger::println("DtoConstStructInitializer: %s", si->toChars()); - LOG_SCOPE; - - // get TypeStruct - assert(si->ad); - TypeStruct* ts = (TypeStruct*)si->ad->type; - - // force constant initialization of the symbol - si->ad->codegen(Type::sir); - - // sanity check - assert(si->value.dim > 0); - assert(si->value.dim == si->vars.dim); - - // vector of final initializer constants - std::vector inits; - - // get the ir struct - IrStruct* irstruct = si->ad->ir.irStruct; - - // get default fields - IrStruct::VarDeclVector& defaults = irstruct->defVars; - size_t ndefaults = defaults.size(); - - // make sure si->vars is sorted by offset - std::vector vars; - size_t nvars = si->vars.dim; - vars.resize(nvars); - - // fill pair vector - for (size_t i = 0; i < nvars; i++) - { - VarDeclaration* var = (VarDeclaration*)si->vars.data[i]; - Initializer* ini = (Initializer*)si->value.data[i]; - assert(var); - assert(ini); - vars[i] = std::make_pair(var, ini); - } - // sort it - qsort(&vars[0], nvars, sizeof(VarInitPair), &varinit_offset_cmp_func); - - // check integrity - // and do error checking, since the frontend does not verify static struct initializers - size_t lastoffset = 0; - size_t lastsize = 0; - bool overlap = false; - for (size_t i=0; i < nvars; i++) - { - // next explicit init var - VarDeclaration* var = vars[i].first; - Logger::println("var = %s : +%u", var->toChars(), var->offset); - - // I would have thought this to be a frontend check - for (size_t j=i+1; joffset >= var->offset && var2->offset < var->offset + var->type->size()) - { - fprintf(stdmsg, "Error: %s: initializer '%s' overlaps with '%s'\n", si->loc.toChars(), var->toChars(), var2->toChars()); - overlap = true; - } - } - - // update offsets - lastoffset = var->offset; - lastsize = var->type->size(); - } - - // error handling, report all overlaps before aborting - if (overlap) - { - error("%s: overlapping union initializers", si->loc.toChars()); - } - - // go through each explicit initalizer, falling back to defaults or zeros when necessary - lastoffset = 0; - lastsize = 0; - - size_t j=0; // defaults - - for (size_t i=0; i < nvars; i++) - { - // get var and init - VarDeclaration* var = vars[i].first; - Initializer* ini = vars[i].second; - - size_t offset = var->offset; - size_t size = var->type->size(); - - // if there is space before the next explicit initializer -Lpadding: - size_t pos = lastoffset+lastsize; - if (offset > pos) - { - // find the the next default initializer that fits in this space - VarDeclaration* nextdef = nextDefault(irstruct, j, lastoffset+lastsize, offset); - - // found - if (nextdef) - { - // need zeros before the default - if (nextdef->offset > pos) - { - Logger::println("inserting %lu byte padding at %lu", nextdef->offset - pos, pos); - addZeros(inits, pos, nextdef->offset); - } - - // do the default - Logger::println("adding default field: %s : +%u", nextdef->toChars(), nextdef->offset); - if (!nextdef->ir.irField->constInit) - nextdef->ir.irField->constInit = DtoConstInitializer(nextdef->loc, nextdef->type, nextdef->init); - LLConstant* c = nextdef->ir.irField->constInit; - inits.push_back(c); - - // update offsets - lastoffset = nextdef->offset; - lastsize = nextdef->type->size(); - - // check if more defaults would fit - goto Lpadding; - } - // not found, pad with zeros - else - { - Logger::println("inserting %lu byte padding at %lu", offset - pos, pos); - addZeros(inits, pos, offset); - // offsets are updated by the explicit initializer - } - } - - // insert next explicit - Logger::println("adding explicit field: %s : +%lu", var->toChars(), offset); - LOG_SCOPE; - LLConstant* c = DtoConstInitializer(var->loc, var->type, ini); - inits.push_back(c); - - lastoffset = offset; - lastsize = size; - } - - // there might still be padding after the last one, make sure that is defaulted/zeroed as well - size_t structsize = si->ad->structsize; - - // if there is space before the next explicit initializer - // FIXME: this should be handled in the loop above as well -Lpadding2: - size_t pos = lastoffset+lastsize; - if (structsize > pos) - { - // find the the next default initializer that fits in this space - VarDeclaration* nextdef = nextDefault(irstruct, j, lastoffset+lastsize, structsize); - - // found - if (nextdef) - { - // need zeros before the default - if (nextdef->offset > pos) - { - Logger::println("inserting %lu byte padding at %lu", nextdef->offset - pos, pos); - addZeros(inits, pos, nextdef->offset); - } - - // do the default - Logger::println("adding default field: %s : +%u", nextdef->toChars(), nextdef->offset); - if (!nextdef->ir.irField->constInit) - nextdef->ir.irField->constInit = DtoConstInitializer(nextdef->loc, nextdef->type, nextdef->init); - LLConstant* c = nextdef->ir.irField->constInit; - inits.push_back(c); - - // update offsets - lastoffset = nextdef->offset; - lastsize = nextdef->type->size(); - - // check if more defaults would fit - goto Lpadding2; - } - // not found, pad with zeros - else - { - Logger::println("inserting %lu byte padding at %lu", structsize - pos, pos); - addZeros(inits, pos, structsize); - lastoffset = pos; - lastsize = structsize - pos; - } - } - - assert(lastoffset+lastsize == structsize); - - // make the constant struct - LLConstant* c = LLConstantStruct::get(inits, si->ad->ir.irStruct->packed); - if (Logger::enabled()) - { - Logger::cout() << "constant struct initializer: " << *c << '\n'; - } - assert(getTypePaddedSize(c->getType()) == structsize); - return c; -} - -////////////////////////////////////////////////////////////////////////////////////////// - -std::vector DtoStructLiteralValues(const StructDeclaration* sd, const std::vector& inits) -{ - // get arrays - size_t nvars = sd->fields.dim; - VarDeclaration** vars = (VarDeclaration**)sd->fields.data; - - assert(inits.size() == nvars); - - // first locate all explicit initializers - std::vector explicitInits; - for (size_t i=0; i < nvars; i++) - { - if (inits[i]) - { - explicitInits.push_back(vars[i]); - } - } - - // vector of values to build aggregate from - std::vector values; - - // offset trackers - size_t lastoffset = 0; - size_t lastsize = 0; - - // index of next explicit init - size_t exidx = 0; - // number of explicit inits - size_t nex = explicitInits.size(); - - // for through each field and build up the struct, padding with zeros - size_t i; - for (i=0; ioffset; - size_t sz = var->type->size(); - - // get next explicit - VarDeclaration* nextVar = NULL; - size_t nextOs = 0; - if (exidx < nex) - { - nextVar = explicitInits[exidx]; - nextOs = nextVar->offset; - } - // none, rest is defaults - else - { - break; - } - - // not explicit initializer, default initialize if there is room, otherwise skip - if (!inits[i]) - { - // default init if there is room - // (past current offset) and (small enough to fit before next explicit) - if ((os >= lastoffset + lastsize) && (os+sz <= nextOs)) - { - // add any 0 padding needed before this field - if (os > lastoffset + lastsize) - { - //printf("1added %lu zeros\n", os - lastoffset - lastsize); - addZeros(values, lastoffset + lastsize, os); - } - - // get field default init - IrField* f = var->ir.irField; - assert(f); - if (!f->constInit) - f->constInit = DtoConstInitializer(var->loc, var->type, var->init); - - values.push_back(f->constInit); - - lastoffset = os; - lastsize = sz; - //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz); - } - // skip - continue; - } - - assert(nextVar == var); - - // add any 0 padding needed before this field - if (os > lastoffset + lastsize) - { - //printf("added %lu zeros\n", os - lastoffset - lastsize); - addZeros(values, lastoffset + lastsize, os); - } - - // add the expression value - values.push_back(inits[i]); - - // update offsets - lastoffset = os; - lastsize = sz; - - // go to next explicit init - exidx++; - - //printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz); - } - - // fill out rest with default initializers - const LLType* structtype = DtoType(sd->type); - size_t structsize = getTypePaddedSize(structtype); - - // FIXME: this could probably share some code with the above - if (structsize > lastoffset+lastsize) - { - for (/*continue from first loop*/; i < nvars; i++) - { - VarDeclaration* var = vars[i]; - - // get var info - size_t os = var->offset; - size_t sz = var->type->size(); - - // skip? - if (os < lastoffset + lastsize) - continue; - - // add any 0 padding needed before this field - if (os > lastoffset + lastsize) - { - //printf("2added %lu zeros\n", os - lastoffset - lastsize); - addZeros(values, lastoffset + lastsize, os); - } - - // get field default init - IrField* f = var->ir.irField; - assert(f); - if (!f->constInit) - f->constInit = DtoConstInitializer(var->loc, var->type, var->init); - - values.push_back(f->constInit); - - lastoffset = os; - lastsize = sz; - //printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz); - } - } - - // add any 0 padding needed at the end of the literal - if (structsize > lastoffset+lastsize) - { - //printf("3added %lu zeros\n", structsize - lastoffset - lastsize); - addZeros(values, lastoffset + lastsize, structsize); - } - - return values; -} +#include "ir/irtypestruct.h" ////////////////////////////////////////////////////////////////////////////////////////// @@ -490,10 +62,6 @@ ////////////////////////////////////////////////////////////////////////////////////////// -static void DtoDeclareStruct(StructDeclaration* sd); -static void DtoConstInitStruct(StructDeclaration* sd); -static void DtoDefineStruct(StructDeclaration* sd); - void DtoResolveStruct(StructDeclaration* sd) { // don't do anything if already been here @@ -505,185 +73,38 @@ Logger::println("Resolving struct type: %s (%s)", sd->toChars(), sd->locToChars()); LOG_SCOPE; - // get the DMD TypeStruct - TypeStruct* ts = (TypeStruct*)sd->type; + // make sure type exists + DtoType(sd->type); // create the IrStruct IrStruct* irstruct = new IrStruct(sd); sd->ir.irStruct = irstruct; - // create the type - ts->ir.type = new LLPATypeHolder(llvm::OpaqueType::get()); - - // create symbols we're going to need - // avoids chicken egg problems - std::string initname("_D"); - initname.append(sd->mangle()); - initname.append("6__initZ"); - - llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(sd); - sd->ir.irStruct->init = new llvm::GlobalVariable(sd->ir.irStruct->initOpaque.get(), true, _linkage, NULL, initname, gIR->module); - - // handle forward declaration structs (opaques) - // didn't even know D had those ... - if (sd->sizeok != 1) - { - // nothing more to do - return; - } - - // make this struct current - gIR->structs.push_back(irstruct); - - // get some info - bool ispacked = (ts->alignsize() == 1); - - // set irstruct info - irstruct->packed = ispacked; + // emit the initZ symbol + LLGlobalVariable* initZ = irstruct->getInitSymbol(); - // methods, fields - Array* arr = sd->members; - for (int k=0; k < arr->dim; k++) { - Dsymbol* s = (Dsymbol*)arr->data[k]; - s->codegen(Type::sir); - } - - const LLType* ST = irstruct->build(); - -#if 0 - std::cout << sd->kind() << ' ' << sd->toPrettyChars() << " type: " << *ST << '\n'; - - // add fields - for (int k=0; k < fields->dim; k++) + // perform definition + if (mustDefineSymbol(sd)) { - VarDeclaration* v = (VarDeclaration*)fields->data[k]; - printf(" field: %s %s\n", v->type->toChars(), v->toChars()); - printf(" index: %u offset: %u\n", v->ir.irField->index, v->ir.irField->unionOffset); - } - - unsigned llvmSize = (unsigned)getTypePaddedSize(ST); - unsigned dmdSize = (unsigned)sd->type->size(); - printf(" llvm size: %u dmd size: %u\n", llvmSize, dmdSize); - assert(llvmSize == dmdSize); - -#endif - - /*for (int k=0; k < sd->members->dim; k++) { - Dsymbol* dsym = (Dsymbol*)(sd->members->data[k]); - dsym->toObjFile(); - }*/ - - Logger::println("doing struct fields"); - - // refine abstract types for stuff like: struct S{S* next;} - llvm::cast(ts->ir.type->get())->refineAbstractTypeTo(ST); - ST = ts->ir.type->get(); - - // name type - if (sd->parent->isModule()) { - gIR->module->addTypeName(sd->mangle(),ST); + // set initZ initializer + initZ->setInitializer(irstruct->getDefaultInit()); } - // emit functions - size_t n = irstruct->structFuncs.size(); - for (size_t i = 0; i < n; ++i) + // emit members + if (sd->members) { - DtoResolveFunction(irstruct->structFuncs[i]); - } - irstruct->structFuncs.clear(); - - gIR->structs.pop_back(); - - DtoDeclareStruct(sd); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void DtoDeclareStruct(StructDeclaration* sd) -{ - DtoResolveStruct(sd); - - if (sd->ir.declared) return; - sd->ir.declared = true; - - Logger::println("DtoDeclareStruct(%s): %s", sd->toChars(), sd->loc.toChars()); - LOG_SCOPE; - - TypeStruct* ts = (TypeStruct*)sd->type->toBasetype(); - - DtoConstInitStruct(sd); - if (mustDefineSymbol(sd)) - DtoDefineStruct(sd); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void DtoConstInitStruct(StructDeclaration* sd) -{ - DtoDeclareStruct(sd); - - if (sd->ir.initialized) return; - sd->ir.initialized = true; - - Logger::println("DtoConstInitStruct(%s): %s", sd->toChars(), sd->loc.toChars()); - LOG_SCOPE; - - IrStruct* irstruct = sd->ir.irStruct; - gIR->structs.push_back(irstruct); - - const llvm::StructType* structtype = isaStruct(sd->type->ir.type->get()); - - // always generate the constant initalizer - assert(!irstruct->constInit); - if (sd->zeroInit) - { - Logger::println("Zero initialized"); - irstruct->constInit = llvm::ConstantAggregateZero::get(structtype); - } - else - { - Logger::println("Not zero initialized"); - - LLConstant* c = irstruct->buildDefaultConstInit(); - irstruct->constInit = c; + ArrayIter it(*sd->members); + while (!it.done()) + { + Dsymbol* member = it.get(); + if (member) + member->codegen(Type::sir); + it.next(); + } } - // refine __initZ global type to the one of the initializer - llvm::cast(irstruct->initOpaque.get())->refineAbstractTypeTo(irstruct->constInit->getType()); - - // build initializers for static member variables - size_t n = irstruct->staticVars.size(); - for (size_t i = 0; i < n; ++i) - { - DtoConstInitGlobal(irstruct->staticVars[i]); - } - // This is all we use it for. Clear the memory! - irstruct->staticVars.clear(); - - gIR->structs.pop_back(); - // emit typeinfo - if (sd->getModule() == gIR->dmodule && sd->llvmInternal != LLVMno_typeinfo) - DtoTypeInfoOf(sd->type, false); -} - -////////////////////////////////////////////////////////////////////////////////////////// - -static void DtoDefineStruct(StructDeclaration* sd) -{ - DtoConstInitStruct(sd); - - if (sd->ir.defined) return; - sd->ir.defined = true; - - Logger::println("DtoDefineStruct(%s): %s", sd->toChars(), sd->loc.toChars()); - LOG_SCOPE; - - assert(sd->type->ty == Tstruct); - TypeStruct* ts = (TypeStruct*)sd->type; - sd->ir.irStruct->init->setInitializer(sd->ir.irStruct->constInit); - - sd->ir.DModule = gIR->dmodule; + DtoTypeInfoOf(sd->type); } ////////////////////////////////////////////////////////////////////////////////////////// diff -r 08f87d8cd101 -r 79758fd2f48a gen/todebug.cpp --- a/gen/todebug.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/todebug.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -13,6 +13,7 @@ #include "gen/logger.h" #include "gen/llvmhelpers.h" #include "gen/linkage.h" +#include "gen/utils.h" #include "ir/irmodule.h" @@ -288,14 +289,12 @@ std::vector elems; if (!ir->aggrdecl->isInterfaceDeclaration()) // plain interfaces don't have one { - std::vector& arr = ir->varDecls; - size_t narr = arr.size(); + ArrayIter it(sd->fields); + size_t narr = sd->fields.dim; elems.reserve(narr); - for (int k=0; kloc.linnum, vd->type, compileUnit, definedCU, vd->toChars(), vd->offset).getGV(); elems.push_back(DBG_CAST(ptr)); } diff -r 08f87d8cd101 -r 79758fd2f48a gen/toir.cpp --- a/gen/toir.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/toir.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -131,8 +131,7 @@ { Logger::println("ClassInfoDeclaration: %s", cid->cd->toChars()); cid->cd->codegen(Type::sir);; - assert(cid->cd->ir.irStruct->classInfo); - return new DVarValue(type, vd, cid->cd->ir.irStruct->classInfo); + return new DVarValue(type, vd, cid->cd->ir.irStruct->getClassInfoSymbol()); } // nested variable #if DMDV2 @@ -216,8 +215,8 @@ TypeStruct* ts = (TypeStruct*)sdecltype; assert(ts->sym); ts->sym->codegen(Type::sir); - assert(ts->sym->ir.irStruct->init); - return new DVarValue(type, ts->sym->ir.irStruct->init); + + return new DVarValue(type, ts->sym->ir.irStruct->getInitSymbol()); } else { @@ -242,8 +241,8 @@ assert(sdecltype->ty == Tstruct); TypeStruct* ts = (TypeStruct*)sdecltype; ts->sym->codegen(Type::sir); - assert(ts->sym->ir.irStruct->constInit); - return ts->sym->ir.irStruct->constInit; + + return ts->sym->ir.irStruct->getDefaultInit(); } if (TypeInfoDeclaration* ti = var->isTypeInfoDeclaration()) @@ -1134,9 +1133,7 @@ size_t vtblidx = fdecl->vtblIndex; if (Logger::enabled()) Logger::cout() << "vthis: " << *vthis << '\n'; - funcval = vthis; - if (!fdecl->isMember2()->isInterfaceDeclaration()) - funcval = DtoGEP(funcval, zero, zero); + funcval = DtoGEP(vthis, zero, zero); funcval = DtoLoad(funcval); Logger::println("vtblidx = %lu", vtblidx); funcval = DtoGEP(funcval, zero, DtoConstUint(vtblidx), toChars()); @@ -1646,7 +1643,7 @@ else { assert(ts->sym); ts->sym->codegen(Type::sir); - DtoAggrCopy(mem,ts->sym->ir.irStruct->init); + DtoAggrCopy(mem,ts->sym->ir.irStruct->getInitSymbol()); } return new DImValue(type, mem); } @@ -1658,8 +1655,7 @@ DVarValue tmpvar(newtype, mem); // default initialize - // FIXME: should this use DtoConstExpInit instead ? - // or is static arrays the only troublemaker? + // static arrays never appear here, so using the defaultInit is ok! Expression* exp = newtype->defaultInit(loc); DValue* iv = exp->toElem(gIR); DtoAssign(loc, &tmpvar, iv); @@ -2413,7 +2409,8 @@ } // vector of values to build aggregate from - std::vector values = DtoStructLiteralValues(sd, inits); + std::vector values;// = DtoStructLiteralValues(sd, inits); + assert(0 && "struct literal exp todo"); // get the struct type from the values size_t n = values.size(); @@ -2462,7 +2459,8 @@ inits[i] = exprs[i]->toConstElem(p); // vector of values to build aggregate from - std::vector values = DtoStructLiteralValues(sd, inits); + std::vector values;// = DtoStructLiteralValues(sd, inits); + assert(0 && "struct literal const exp todo"); // we know those values are constants.. cast them std::vector constvals(values.size(), NULL); diff -r 08f87d8cd101 -r 79758fd2f48a gen/tollvm.cpp --- a/gen/tollvm.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/tollvm.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -23,6 +23,7 @@ #include "gen/llvm-version.h" #include "ir/irtype.h" +#include "ir/irtypeclass.h" bool DtoIsPassedByRef(Type* type) { @@ -52,11 +53,17 @@ const LLType* DtoType(Type* t) { +#if DMDV2 + t = t->mutableOf(); +#endif + if (t->irtype) { return t->irtype->get(); } + IF_LOG Logger::println("Building type: %s", t->toChars()); + assert(t); switch (t->ty) { @@ -86,57 +93,50 @@ case Tdchar: { t->irtype = new IrTypeBasic(t); - return t->irtype->get(); + return t->irtype->buildType(); } // pointers case Tpointer: { t->irtype = new IrTypePointer(t); - return t->irtype->get(); + return t->irtype->buildType(); } // arrays case Tarray: { t->irtype = new IrTypeArray(t); - return t->irtype->get(); + return t->irtype->buildType(); } case Tsarray: { t->irtype = new IrTypeSArray(t); - return t->irtype->get(); + return t->irtype->buildType(); } // aggregates case Tstruct: { - #if DMDV2 - TypeStruct* ts = (TypeStruct*)t->mutableOf(); - #else TypeStruct* ts = (TypeStruct*)t; - #endif - assert(ts->sym); - DtoResolveDsymbol(ts->sym); - return ts->ir.type->get(); + t->irtype = new IrTypeStruct(ts->sym); + return t->irtype->buildType(); } - case Tclass: { - #if DMDV2 - TypeClass* tc = (TypeClass*)t->mutableOf(); - #else TypeClass* tc = (TypeClass*)t; - #endif - assert(tc->sym); - DtoResolveDsymbol(tc->sym); - return getPtrToType(tc->ir.type->get()); + t->irtype = new IrTypeClass(tc->sym); + return t->irtype->buildType(); } // functions case Tfunction: { if (!t->ir.type || *t->ir.type == NULL) { - return DtoFunctionType(t,NULL,NULL); + TypeFunction* tf = (TypeFunction*)t; + if (tf->funcdecl) + return DtoFunctionType(tf->funcdecl); + else + return DtoFunctionType(tf,NULL,NULL); } else { return t->ir.type->get(); @@ -156,6 +156,8 @@ // typedefs // enum + + // FIXME: maybe just call toBasetype first ? case Ttypedef: case Tenum: { @@ -166,15 +168,7 @@ // associative arrays case Taarray: - #if 1 return getVoidPtrType(); - #else - { - TypeAArray* taa = (TypeAArray*)t; - // aa key/val can't be void - return getPtrToType(LLStructType::get(DtoType(taa->key), DtoType(taa->next), 0)); - } - #endif /* Not needed atm as VarDecls for tuples are rewritten as a string of diff -r 08f87d8cd101 -r 79758fd2f48a gen/toobj.cpp --- a/gen/toobj.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/toobj.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -146,7 +146,7 @@ sir->emitFunctionBodies(); // generate ModuleInfo - genmoduleinfo(); + //genmoduleinfo(); // emit usedArray if (!ir.usedArray.empty()) @@ -621,7 +621,7 @@ LLConstant* c = 0; // vtable - c = moduleinfo->ir.irStruct->vtbl; + c = moduleinfo->ir.irStruct->getVtblSymbol(); initVec.push_back(c); // monitor @@ -696,8 +696,7 @@ continue; } Logger::println("class: %s", cd->toPrettyChars()); - assert(cd->ir.irStruct->classInfo); - c = DtoBitCast(cd->ir.irStruct->classInfo, getPtrToType(classinfoTy)); + c = DtoBitCast(cd->ir.irStruct->getClassInfoSymbol(), getPtrToType(classinfoTy)); classInits.push_back(c); } // has class array? diff -r 08f87d8cd101 -r 79758fd2f48a gen/typinf.cpp --- a/gen/typinf.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/gen/typinf.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -253,20 +253,6 @@ /* ========================================================================= */ -/*************************************** - * Create a static array of TypeInfo references - * corresponding to an array of Expression's. - * Used to supply hidden _arguments[] value for variadic D functions. - */ - -Expression *createTypeInfoArray(Scope *sc, Expression *exps[], int dim) -{ - assert(0); // done elsewhere in LDC - return NULL; -} - -/* ========================================================================= */ - ////////////////////////////////////////////////////////////////////////////// // MAGIC PLACE ////////////////////////////////////////////////////////////////////////////// @@ -376,7 +362,7 @@ // vtbl std::vector sinits; - sinits.push_back(base->ir.irStruct->vtbl); + sinits.push_back(base->ir.irStruct->getVtblSymbol()); // monitor sinits.push_back(getNullPtr(getPtrToType(LLType::Int8Ty))); @@ -433,7 +419,7 @@ // vtbl std::vector sinits; - sinits.push_back(base->ir.irStruct->vtbl); + sinits.push_back(base->ir.irStruct->getVtblSymbol()); // monitor sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty))); @@ -491,7 +477,7 @@ // vtbl std::vector sinits; - sinits.push_back(base->ir.irStruct->vtbl); + sinits.push_back(base->ir.irStruct->getVtblSymbol()); // monitor sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty))); @@ -553,7 +539,7 @@ // initializer vector std::vector sinits; // first is always the vtable - sinits.push_back(base->ir.irStruct->vtbl); + sinits.push_back(base->ir.irStruct->getVtblSymbol()); // monitor sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty))); @@ -592,7 +578,7 @@ // initializer vector std::vector sinits; // first is always the vtable - sinits.push_back(base->ir.irStruct->vtbl); + sinits.push_back(base->ir.irStruct->getVtblSymbol()); // monitor sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty))); @@ -664,7 +650,7 @@ // vtbl std::vector sinits; - sinits.push_back(base->ir.irStruct->vtbl); + sinits.push_back(base->ir.irStruct->getVtblSymbol()); // monitor sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty))); @@ -687,7 +673,7 @@ #endif { size_t cisize = getTypeStoreSize(tc->ir.type->get()); - LLConstant* cicast = llvm::ConstantExpr::getBitCast(sd->ir.irStruct->init, initpt); + LLConstant* cicast = llvm::ConstantExpr::getBitCast(sd->ir.irStruct->getInitSymbol(), initpt); sinits.push_back(DtoConstSlice(DtoConstSize_t(cisize), cicast)); } @@ -857,7 +843,7 @@ // initializer vector std::vector sinits; // first is always the vtable - sinits.push_back(base->ir.irStruct->vtbl); + sinits.push_back(base->ir.irStruct->getVtblSymbol()); // monitor sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty))); @@ -865,9 +851,10 @@ // get classinfo assert(tinfo->ty == Tclass); TypeClass *tc = (TypeClass *)tinfo; - tc->sym->codegen(Type::sir);; - assert(tc->sym->ir.irStruct->classInfo); - sinits.push_back(tc->sym->ir.irStruct->classInfo); + + tc->sym->codegen(Type::sir); + + sinits.push_back(tc->sym->ir.irStruct->getClassInfoSymbol()); // create the inititalizer LLConstant* tiInit = llvm::ConstantStruct::get(sinits); @@ -897,7 +884,7 @@ // initializer vector std::vector sinits; // first is always the vtable - sinits.push_back(base->ir.irStruct->vtbl); + sinits.push_back(base->ir.irStruct->getVtblSymbol()); // monitor sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty))); @@ -905,8 +892,8 @@ // get classinfo assert(tinfo->ty == Tclass); TypeClass *tc = (TypeClass *)tinfo; - assert(tc->sym->ir.irStruct->classInfo); - sinits.push_back(tc->sym->ir.irStruct->classInfo); + + sinits.push_back(tc->sym->ir.irStruct->getClassInfoSymbol()); // create the inititalizer LLConstant* tiInit = llvm::ConstantStruct::get(sinits); @@ -936,7 +923,7 @@ // initializer vector std::vector sinits; // first is always the vtable - sinits.push_back(base->ir.irStruct->vtbl); + sinits.push_back(base->ir.irStruct->getVtblSymbol()); // monitor sinits.push_back(llvm::ConstantPointerNull::get(getPtrToType(LLType::Int8Ty))); diff -r 08f87d8cd101 -r 79758fd2f48a gen/utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/utils.h Wed Apr 15 20:06:25 2009 +0200 @@ -0,0 +1,46 @@ +#ifndef __LDC_GEN_UTILS_H__ +#define __LDC_GEN_UTILS_H__ + +#include "root.h" + +/// Very simple templated iterator for DMD ArrayS. +template +struct ArrayIter +{ + Array& array; + size_t index; + + ArrayIter(Array& arr, size_t idx = 0) + : array(arr), index(idx) + { } + + bool done() + { + return index >= array.dim; + } + bool more() + { + return index < array.dim; + } + + C* get() + { + return static_cast(array.data[index]); + } + C* operator->() + { + return static_cast(array.data[index]); + } + + void next() + { + ++index; + } +}; + +// some aliases +typedef ArrayIter DsymbolIter; +typedef ArrayIter FuncDeclarationIter; +typedef ArrayIter VarDeclarationIter; + +#endif diff -r 08f87d8cd101 -r 79758fd2f48a ir/irclass.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ir/irclass.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -0,0 +1,441 @@ +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" + +#include "aggregate.h" +#include "declaration.h" +#include "mtype.h" + +#include "gen/irstate.h" +#include "gen/logger.h" +#include "gen/tollvm.h" +#include "gen/llvmhelpers.h" +#include "gen/utils.h" +#include "gen/arrays.h" + +#include "ir/irstruct.h" +#include "ir/irtypeclass.h" + +////////////////////////////////////////////////////////////////////////////// + +extern LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init); +extern size_t add_zeros(std::vector& constants, size_t diff); + +extern LLConstant* DtoDefineClassInfo(ClassDeclaration* cd); + +////////////////////////////////////////////////////////////////////////////// + +LLGlobalVariable * IrStruct::getVtblSymbol() +{ + if (vtbl) + return vtbl; + + // create the initZ symbol + std::string initname("_D"); + initname.append(aggrdecl->mangle()); + initname.append("6__vtblZ"); + + llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); + + const LLType* vtblTy = type->irtype->isClass()->getVtbl(); + + vtbl = new llvm::GlobalVariable( + vtblTy, true, _linkage, NULL, initname, gIR->module); + + return vtbl; +} + +////////////////////////////////////////////////////////////////////////////// + +LLGlobalVariable * IrStruct::getClassInfoSymbol() +{ + if (classInfo) + return classInfo; + + // create the initZ symbol + std::string initname("_D"); + initname.append(aggrdecl->mangle()); + if (aggrdecl->isInterfaceDeclaration()) + initname.append("11__InterfaceZ"); + else + initname.append("7__ClassZ"); + + llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); + + ClassDeclaration* cinfo = ClassDeclaration::classinfo; + DtoType(cinfo->type); + IrTypeClass* tc = cinfo->type->irtype->isClass(); + assert(tc && "invalid ClassInfo type"); + + classInfo = new llvm::GlobalVariable( + tc->getPA().get(), true, _linkage, NULL, initname, gIR->module); + + return classInfo; +} + +////////////////////////////////////////////////////////////////////////////// + +LLGlobalVariable * IrStruct::getInterfaceArraySymbol() +{ + if (classInterfacesArray) + return classInterfacesArray; + + ClassDeclaration* cd = aggrdecl->isClassDeclaration(); + + assert(cd->vtblInterfaces && cd->vtblInterfaces->dim > 0 && + "should not create interface info array for class with no explicit " + "interface implementations") + + VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3); + const llvm::Type* InterfaceTy = DtoType(idx->type); + + // create Interface[N] + const llvm::ArrayType* array_type = llvm::ArrayType::get( + InterfaceTy, + cd->vtblInterfaces->dim); + + // put it in a global + std::string name("_D"); + name.append(cd->mangle()); + name.append("16__interfaceInfosZ"); + classInterfacesArray = new llvm::GlobalVariable(array_type, true, DtoLinkage(cd), NULL, name, classInfo); + + return classInterfacesArray; +} + +////////////////////////////////////////////////////////////////////////////// + +LLConstant * IrStruct::getVtblInit() +{ + if (constVtbl) + return constVtbl; + + IF_LOG Logger::println("Building vtbl initializer"); + LOG_SCOPE; + + ClassDeclaration* cd = aggrdecl->isClassDeclaration(); + assert(cd && "not class"); + + std::vector constants; + constants.reserve(cd->vtbl.dim); + + // start with the classinfo + llvm::Constant* c = getClassInfoSymbol(); + c = DtoBitCast(c, DtoType(ClassDeclaration::classinfo->type)); + constants.push_back(c); + + // add virtual function pointers + size_t n = cd->vtbl.dim; + for (size_t i = 1; i < n; i++) + { + Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[i]; + assert(dsym && "null vtbl member"); + + FuncDeclaration* fd = dsym->isFuncDeclaration(); + assert(fd && "vtbl entry not a function"); + + if (fd->isAbstract() && !fd->fbody) + { + c = getNullValue(DtoType(fd->type->pointerTo())); + } + else + { + fd->codegen(Type::sir); + assert(fd->ir.irFunc && "invalid vtbl function"); + c = fd->ir.irFunc->func; + } + constants.push_back(c); + } + + // build the constant struct + constVtbl = llvm::ConstantStruct::get(constants, false); + + // sanity check +#if 0 + IF_LOG Logger::cout() << "constVtbl type: " << *constVtbl->getType() << std::endl; + IF_LOG Logger::cout() << "vtbl type: " << *type->irtype->isClass()->getVtbl() << std::endl; +#endif + + assert(constVtbl->getType() == type->irtype->isClass()->getVtbl() && + "vtbl initializer type mismatch"); + + return constVtbl; +} + +////////////////////////////////////////////////////////////////////////////// + +LLConstant * IrStruct::getClassInfoInit() +{ + if (constClassInfo) + return constClassInfo; + constClassInfo = DtoDefineClassInfo(aggrdecl->isClassDeclaration()); + return constClassInfo; +} + +////////////////////////////////////////////////////////////////////////////// + +void IrStruct::addBaseClassInits( + std::vector& constants, + ClassDeclaration* base, + size_t& offset, + size_t& field_index) +{ + if (base->baseClass) + { + addBaseClassInits(constants, base->baseClass, offset, field_index); + } + + ArrayIter it(base->fields); + for (; !it.done(); it.next()) + { + VarDeclaration* vd = it.get(); + + // skip if offset moved backwards + if (vd->offset < offset) + { + IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset); + continue; + } + + IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); + LOG_SCOPE; + + // get next aligned offset for this type + size_t alignsize = vd->type->alignsize(); + size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); + + // insert explicit padding? + if (alignedoffset < vd->offset) + { + add_zeros(constants, vd->offset - alignedoffset); + } + + // add default type + constants.push_back(get_default_initializer(vd, vd->init)); + + // advance offset to right past this field + offset = vd->offset + vd->type->size(); + } + + // has interface vtbls? + if (base->vtblInterfaces) + { + // false when it's not okay to use functions from super classes + bool newinsts = (base == aggrdecl->isClassDeclaration()); + + ArrayIter it2(*base->vtblInterfaces); + for (; !it2.done(); it2.next()) + { + BaseClass* b = it2.get(); + constants.push_back(getInterfaceVtbl(b, newinsts)); + offset += PTRSIZE; + } + } + + // tail padding? + if (offset < base->structsize) + { + add_zeros(constants, base->structsize - offset); + offset = base->structsize; + } +} + +////////////////////////////////////////////////////////////////////////////// + +LLConstant * IrStruct::createClassDefaultInitializer() +{ + ClassDeclaration* cd = aggrdecl->isClassDeclaration(); + assert(cd && "invalid class aggregate"); + + IF_LOG Logger::println("Building class default initializer %s @ %s", cd->toPrettyChars(), cd->locToChars()); + LOG_SCOPE; + IF_LOG Logger::println("Instance size: %u", cd->structsize); + + // find the fields that contribute to the default initializer. + // these will define the default type. + + std::vector constants; + constants.reserve(32); + + // add vtbl + constants.push_back(getVtblSymbol()); + // add monitor + constants.push_back(getNullValue(DtoType(Type::tvoid->pointerTo()))); + + // we start right after the vtbl and monitor + size_t offset = PTRSIZE * 2; + size_t field_index = 2; + + // add data members recursively + addBaseClassInits(constants, cd, offset, field_index); + + // build the constant + llvm::Constant* definit = llvm::ConstantStruct::get(constants, false); + + // sanity check + assert(definit->getType() == type->irtype->getPA().get() && "class initializer type mismatch"); + + return definit; +} + +////////////////////////////////////////////////////////////////////////////// + +llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instance) +{ + ClassDeclaration* cd = aggrdecl->isClassDeclaration(); + assert(cd && "not a class aggregate"); + + ClassGlobalMap::iterator it = interfaceVtblMap.find(cd); + if (it != interfaceVtblMap.end()) + return it->second; + + IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s", + b->base->toPrettyChars(), aggrdecl->toPrettyChars()); + LOG_SCOPE; + + Array vtbl_array; + b->fillVtbl(cd, &vtbl_array, new_instance); + + std::vector constants; + constants.reserve(vtbl_array.dim); + + // start with the interface info + llvm::Constant* c = getNullValue(DtoType(Type::tvoid->pointerTo())); + constants.push_back(c); + + // add virtual function pointers + size_t n = vtbl_array.dim; + for (size_t i = 1; i < n; i++) + { + Dsymbol* dsym = (Dsymbol*)vtbl_array.data[i]; + assert(dsym && "null vtbl member"); + + FuncDeclaration* fd = dsym->isFuncDeclaration(); + assert(fd && "vtbl entry not a function"); + + assert(!(fd->isAbstract() && !fd->fbody) && + "null symbol in interface implementation vtable"); + + fd->codegen(Type::sir); + assert(fd->ir.irFunc && "invalid vtbl function"); + + constants.push_back(fd->ir.irFunc->func); + } + + // build the vtbl constant + llvm::Constant* vtbl_constant = llvm::ConstantStruct::get(constants, false); + + // create the global variable to hold it + llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); + + std::string mangle("_D"); + mangle.append(cd->mangle()); + mangle.append("11__interface"); + mangle.append(b->base->mangle()); + mangle.append("6__vtblZ"); + + llvm::GlobalVariable* GV = new llvm::GlobalVariable( + vtbl_constant->getType(), + true, + _linkage, + vtbl_constant, + mangle, + gIR->module + ); + + interfaceVtblMap.insert(std::make_pair(b->base, GV)); + + return GV; +} + +////////////////////////////////////////////////////////////////////////////// + +LLConstant * IrStruct::getClassInfoInterfaces() +{ + IF_LOG Logger::println("Building ClassInfo.interfaces"); + LOG_SCOPE; + + ClassDeclaration* cd = aggrdecl->isClassDeclaration(); + assert(cd); + + if (!cd->vtblInterfaces || cd->vtblInterfaces->dim == 0) + { + VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3); + return getNullValue(DtoType(idx->type)); + } + +// Build array of: +// +// struct Interface +// { +// ClassInfo classinfo; +// void*[] vtbl; +// ptrdiff_t offset; +// } + + LLSmallVector constants; + constants.reserve(cd->vtblInterfaces->dim); + + const LLType* classinfo_type = DtoType(ClassDeclaration::classinfo->type); + const LLType* voidptrptr_type = DtoType( + Type::tvoid->pointerTo()->pointerTo()); + + const LLType* our_type = type->irtype->isClass()->getPA().get(); + + ArrayIter it(*cd->vtblInterfaces); + while (it.more()) + { + IF_LOG Logger::println("Adding interface %s", it->base->toPrettyChars()); + + IrStruct* irinter = it->base->ir.irStruct; + assert(irinter && "interface has null IrStruct"); + IrTypeClass* itc = irinter->type->irtype->isClass(); + assert(itc && "null interface IrTypeClass"); + + // classinfo + LLConstant* ci = irinter->getClassInfoSymbol(); + ci = DtoBitCast(ci, classinfo_type); + + // vtbl + ClassGlobalMap::iterator itv = interfaceVtblMap.find(it->base); + assert(itv != interfaceVtblMap.end() && "interface vtbl not found"); + LLConstant* vtb = itv->second; + vtb = DtoBitCast(vtb, voidptrptr_type); + vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb); + + // offset + LLConstant* off = DtoConstSize_t(it->offset); + + // create Interface struct + LLConstant* inits[3] = { ci, vtb, off }; + LLConstant* entry = llvm::ConstantStruct::get(inits, 3); + constants.push_back(entry); + + // next + it.next(); + } + + // create Interface[N] + const llvm::ArrayType* array_type = llvm::ArrayType::get( + constants[0]->getType(), + cd->vtblInterfaces->dim); + + LLConstant* arr = llvm::ConstantArray::get( + array_type, + &constants[0], + constants.size()); + + // apply the initializer + classInterfacesArray->setInitializer(arr); + + LLConstant* idxs[2] = { + DtoConstSize_t(0), + DtoConstSize_t(0) + }; + + // return as a slice + return DtoConstSlice( + DtoConstSize_t(cd->vtblInterfaces->dim), + llvm::ConstantExpr::getGetElementPtr(classInterfacesArray, idxs, 2)); +} + +////////////////////////////////////////////////////////////////////////////// diff -r 08f87d8cd101 -r 79758fd2f48a ir/irlandingpad.cpp --- a/ir/irlandingpad.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/ir/irlandingpad.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -128,7 +128,7 @@ } assert(it->catchType); assert(it->catchType->ir.irStruct); - selectorargs.insert(selectorargs.begin(), it->catchType->ir.irStruct->classInfo); + selectorargs.insert(selectorargs.begin(), it->catchType->ir.irStruct->getClassInfoSymbol()); } } // if there's a finally, the eh table has to have a 0 action diff -r 08f87d8cd101 -r 79758fd2f48a ir/irstruct.cpp --- a/ir/irstruct.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/ir/irstruct.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -5,353 +5,330 @@ #include "declaration.h" #include "init.h" -#include "ir/irstruct.h" #include "gen/irstate.h" #include "gen/tollvm.h" #include "gen/logger.h" #include "gen/llvmhelpers.h" +#include "gen/utils.h" -IrInterface::IrInterface(BaseClass* b) -: vtblInitTy(llvm::OpaqueType::get()) +#include "ir/irstruct.h" +#include "ir/irtypeclass.h" + +////////////////////////////////////////////////////////////////////////////// + +IrStruct::IrStruct(AggregateDeclaration* aggr) +: diCompositeType(NULL) +{ + aggrdecl = aggr; + + type = aggr->type; + + packed = false; + + // above still need to be looked at + + init = NULL; + constInit = NULL; + + vtbl = NULL; + constVtbl = NULL; + classInfo = NULL; + constClassInfo = NULL; + + classInterfacesArray = NULL; +} + +////////////////////////////////////////////////////////////////////////////// + +LLGlobalVariable * IrStruct::getInitSymbol() { - base = b; - decl = b->base; - vtblInit = NULL; - vtbl = NULL; - infoTy = NULL; - infoInit = NULL; - info = NULL; + if (init) + return init; + + // create the initZ symbol + std::string initname("_D"); + initname.append(aggrdecl->mangle()); + initname.append("6__initZ"); + + llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); + + init = new llvm::GlobalVariable( + type->irtype->getPA().get(), true, _linkage, NULL, initname, gIR->module); + + return init; +} - index = 0; +////////////////////////////////////////////////////////////////////////////// + +llvm::Constant * IrStruct::getDefaultInit() +{ + if (constInit) + return constInit; + + if (type->ty == Tstruct) + { + constInit = createStructDefaultInitializer(); + } + else + { + constInit = createClassDefaultInitializer(); + } + + return constInit; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -IrStruct::IrStruct(AggregateDeclaration* aggr) -: initOpaque(llvm::OpaqueType::get()), - classInfoOpaque(llvm::OpaqueType::get()), - vtblTy(llvm::OpaqueType::get()), - vtblInitTy(llvm::OpaqueType::get()), - diCompositeType(NULL) +// helper function that returns the static default initializer of a variable +LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init) { - aggrdecl = aggr; - defaultFound = false; - anon = NULL; - index = 0; - - type = aggr->type; - defined = false; - constinited = false; - - interfaceInfos = NULL; - vtbl = NULL; - constVtbl = NULL; - - init = NULL; - constInit = NULL; - - classInfo = NULL; - constClassInfo = NULL; - classInfoDeclared = false; - classInfoDefined = false; - - packed = false; -} - -IrStruct::~IrStruct() -{ -} - -////////////////////////////////////////// - -void IrStruct::pushAnon(bool isunion) -{ - anon = new Anon(isunion, anon); -} - -////////////////////////////////////////// - -void IrStruct::popAnon() -{ - assert(anon); - - const LLType* BT; - - // get the anon type - if (anon->isunion) + if (init) { - // get biggest type in block - const LLType* biggest = getBiggestType(&anon->types[0], anon->types.size()); - std::vector vec(1, biggest); - BT = LLStructType::get(vec, aggrdecl->ir.irStruct->packed); - } - else - { - // build a struct from the types - BT = LLStructType::get(anon->types, aggrdecl->ir.irStruct->packed); + return DtoConstInitializer(init->loc, vd->type, init); } - - // pop anon - Anon* tmp = anon; - anon = anon->parent; - delete tmp; - - // is there a parent anon? - if (anon) - { - // make sure type gets pushed in the anon, not the main - anon->types.push_back(BT); - // index is only manipulated at the top level, anons use raw offsets - } - // no parent anon, finally add to aggrdecl - else + else if (vd->init) { - types.push_back(BT); - // only advance to next position if main is not a union - if (!aggrdecl->isUnionDeclaration()) - { - index++; - } - } -} - -////////////////////////////////////////// - -void IrStruct::addVar(VarDeclaration * var) -{ - TypeVector* tvec = &types; - if (anon) - { - // make sure type gets pushed in the anon, not the main - tvec = &anon->types; - - // set but don't advance index - var->ir.irField->index = index; - - // set offset in bytes from start of anon block - var->ir.irField->unionOffset = var->offset - var->offset2; - } - else if (aggrdecl->isUnionDeclaration()) - { - // set but don't advance index - var->ir.irField->index = index; + return DtoConstInitializer(vd->init->loc, vd->type, vd->init); } else { - // set and advance index - var->ir.irField->index = index++; - } - - // add type - tvec->push_back(DtoType(var->type)); - - // add var - varDecls.push_back(var); -} - -////////////////////////////////////////// - -const LLType* IrStruct::build() -{ - // if types is empty, add a byte - if (types.empty()) - { - types.push_back(LLType::Int8Ty); - } - - // union type - if (aggrdecl->isUnionDeclaration()) - { - const LLType* biggest = getBiggestType(&types[0], types.size()); - std::vector vec(1, biggest); - return LLStructType::get(vec, aggrdecl->ir.irStruct->packed); - } - // struct/class type - else - { - return LLStructType::get(types, aggrdecl->ir.irStruct->packed); + return DtoConstExpInit(vd->loc, vd->type, vd->type->defaultInit(vd->loc)); } } -void addZeros(std::vector& inits, size_t pos, size_t offset) +// helper function that adds zero bytes to a vector of constants +size_t add_zeros(std::vector& constants, size_t diff) { - assert(offset > pos); - size_t diff = offset - pos; - - size_t sz; - - do + size_t n = constants.size(); + while (diff) { - if (pos%8 == 0 && diff >= 8) - sz = 8; - else if (pos%4 == 0 && diff >= 4) - sz = 4; - else if (pos%2 == 0 && diff >= 2) - sz = 2; - else // if (pos % 1 == 0) - sz = 1; - inits.push_back(LLIntegerType::get(sz*8)); - pos += sz; - diff -= sz; - } while (pos < offset); - - assert(pos == offset); -} - -void addZeros(std::vector& inits, size_t pos, size_t offset) -{ - assert(offset > pos); - size_t diff = offset - pos; - - size_t sz; - - do - { - if (pos%8 == 0 && diff >= 8) - sz = 8; - else if (pos%4 == 0 && diff >= 4) - sz = 4; - else if (pos%2 == 0 && diff >= 2) - sz = 2; - else // if (pos % 1 == 0) - sz = 1; - inits.push_back(LLConstant::getNullValue(LLIntegerType::get(sz*8))); - pos += sz; - diff -= sz; - } while (pos < offset); - - assert(pos == offset); + if (global.params.is64bit && diff % 8 == 0) + { + constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int64Ty)); + diff -= 8; + } + else if (diff % 4 == 0) + { + constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int32Ty)); + diff -= 4; + } + else if (diff % 2 == 0) + { + constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int16Ty)); + diff -= 2; + } + else + { + constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int8Ty)); + diff -= 1; + } + } + return constants.size() - n; } -// FIXME: body is exact copy of above -void addZeros(std::vector& inits, size_t pos, size_t offset) +// Matches the way the type is built in IrTypeStruct +// maybe look at unifying the interface. + +LLConstant * IrStruct::createStructDefaultInitializer() { - assert(offset > pos); - size_t diff = offset - pos; + IF_LOG Logger::println("Building default initializer for %s", aggrdecl->toPrettyChars()); + LOG_SCOPE; + + assert(type->ty == Tstruct && "cannot build struct default initializer for non struct type"); - size_t sz; + // start at offset zero + size_t offset = 0; - do + // vector of constants + std::vector constants; + + // go through fields + ArrayIter it(aggrdecl->fields); + for (; !it.done(); it.next()) { - if (pos%8 == 0 && diff >= 8) - sz = 8; - else if (pos%4 == 0 && diff >= 4) - sz = 4; - else if (pos%2 == 0 && diff >= 2) - sz = 2; - else // if (pos % 1 == 0) - sz = 1; - inits.push_back(LLConstant::getNullValue(LLIntegerType::get(sz*8))); - pos += sz; - diff -= sz; - } while (pos < offset); + VarDeclaration* vd = it.get(); + + if (vd->offset < offset) + { + IF_LOG Logger::println("skipping field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); + continue; + } + + IF_LOG Logger::println("using field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); + + // get next aligned offset for this field + size_t alignedoffset = offset; + if (!packed) + { + size_t alignsize = vd->type->alignsize(); + alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); + } - assert(pos == offset); + // insert explicit padding? + if (alignedoffset < vd->offset) + { + add_zeros(constants, vd->offset - alignedoffset); + } + + // add initializer + constants.push_back(get_default_initializer(vd, NULL)); + + // advance offset to right past this field + offset = vd->offset + vd->type->size(); + } + + // tail padding? + if (offset < aggrdecl->structsize) + { + add_zeros(constants, aggrdecl->structsize - offset); + } + + // build constant struct + llvm::Constant* definit = llvm::ConstantStruct::get(constants, packed); + IF_LOG Logger::cout() << "final default initializer: " << *definit << std::endl; + + // sanity check + assert(definit->getType() == type->irtype->get() && + "default initializer type does not match the default struct type"); + + return definit; } -void IrStruct::buildDefaultConstInit(std::vector& inits) -{ - assert(!defaultFound); - defaultFound = true; +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// yet another rewrite of the notorious StructInitializer. + +// this time a bit more inspired by the DMD code. - const llvm::StructType* structtype = isaStruct(aggrdecl->type->ir.type->get()); - Logger::cout() << "struct type: " << *structtype << '\n'; +LLConstant * IrStruct::createStructInitializer(StructInitializer * si) +{ + IF_LOG Logger::println("Building StructInitializer of type %s", si->ad->toPrettyChars()); + LOG_SCOPE; - size_t lastoffset = 0; - size_t lastsize = 0; - - { - Logger::println("Find the default fields"); - LOG_SCOPE; + // sanity check + assert(si->ad == aggrdecl && "struct type mismatch"); + assert(si->vars.dim == si->value.dim && "inconsistent StructInitializer"); - // go through all vars and find the ones that contribute to the default - size_t nvars = varDecls.size(); - for (size_t i=0; itype->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset); + // array of things to build + typedef std::pair VCPair; + llvm::SmallVector data(aggrdecl->fields.dim); - // only add vars that don't overlap - size_t offset = var->offset; - size_t size = var->type->size(); - if (offset >= lastoffset+lastsize) + // start by creating a map from initializer indices to field indices. + // I have no fucking clue why dmd represents it like this :/ + size_t n = si->vars.dim; + LLSmallVector datamap(n, 0); + for (size_t i = 0; i < n; i++) + { + for (size_t j = 0; 1; j++) + { + assert(j < aggrdecl->fields.dim); + if (aggrdecl->fields.data[j] == si->vars.data[i]) { - Logger::println(" added"); - lastoffset = offset; - lastsize = size; - defVars.push_back(var); + datamap[i] = j; + break; } } } + // fill in explicit initializers + n = si->vars.dim; + for (size_t i = 0; i < n; i++) { - Logger::println("Build the default initializer"); - LOG_SCOPE; + VarDeclaration* vd = (VarDeclaration*)si->vars.data[i]; + Initializer* ini = (Initializer*)si->value.data[i]; - lastoffset = 0; - lastsize = 0; + size_t idx = datamap[i]; - // go through the default vars and build the default constant initializer - // adding zeros along the way to live up to alignment expectations - size_t nvars = defVars.size(); - for (size_t i=0; iloc : si->loc; + error(l, "duplicate initialization of %s", vd->toChars()); + continue; + } - Logger::println("field %s %s = %s : +%u", var->type->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset); + data[idx].first = vd; + data[idx].second = get_default_initializer(vd, ini); + } + + // build array of constants and try to fill in default initializers + // where there is room. + size_t offset = 0; + std::vector constants; + constants.reserve(16); - // get offset and size - size_t offset = var->offset; - size_t size = var->type->size(); + n = data.size(); + for (size_t i = 0; i < n; i++) + { + VarDeclaration* vd = data[i].first; - // is there space in between last last offset and this one? - // if so, fill it with zeros - if (offset > lastoffset+lastsize) + // explicitly initialized? + if (vd != NULL) + { + // get next aligned offset for this field + size_t alignedoffset = offset; + if (!packed) { - size_t pos = lastoffset + lastsize; - addZeros(inits, pos, offset); + size_t alignsize = vd->type->alignsize(); + alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); + } + + // insert explicit padding? + if (alignedoffset < vd->offset) + { + add_zeros(constants, vd->offset - alignedoffset); } - // add the field - // lazily default initialize - if (!var->ir.irField->constInit) - var->ir.irField->constInit = DtoConstInitializer(var->loc, var->type, var->init); - inits.push_back(var->ir.irField->constInit); - - lastoffset = offset; - lastsize = var->type->size(); + IF_LOG Logger::println("using field: %s", vd->toChars()); + constants.push_back(data[i].second); + offset = vd->offset + vd->type->size(); } - - // there might still be padding after the last one, make sure that is zeroed as well - // is there space in between last last offset and this one? - size_t structsize = getTypePaddedSize(structtype); + // not explicit! try and fit in the default initialization instead + // make sure we don't overlap with any following explicity initialized fields + else + { + vd = (VarDeclaration*)aggrdecl->fields.data[i]; - if (structsize > lastoffset+lastsize) - { - size_t pos = lastoffset + lastsize; - addZeros(inits, pos, structsize); + // check all the way that we don't overlap, slow but it works! + for (size_t j = i+1; j <= n; j++) + { + if (j == n) // no overlap + { + IF_LOG Logger::println("using field default: %s", vd->toChars()); + constants.push_back(get_default_initializer(vd, NULL)); + offset = vd->offset + vd->type->size(); + break; + } + + VarDeclaration* vd2 = (VarDeclaration*)aggrdecl->fields.data[j]; + + size_t o2 = vd->offset + vd->type->size(); + + if (vd2->offset < o2 && data[i].first) + break; // overlaps + } } } + + // tail padding? + if (offset < aggrdecl->structsize) + { + add_zeros(constants, aggrdecl->structsize - offset); + } + + // stop if there were errors + if (global.errors) + { + fatal(); + } + + // build constant + assert(!constants.empty()); + llvm::Constant* c = llvm::ConstantStruct::get(&constants[0], constants.size(), packed); + IF_LOG Logger::cout() << "final struct initializer: " << *c << std::endl; + return c; } -LLConstant* IrStruct::buildDefaultConstInit() -{ - // doesn't work for classes, they add stuff before and maybe after data fields - assert(!aggrdecl->isClassDeclaration()); - - // initializer llvm constant list - std::vector inits; - - // just start with an empty list - buildDefaultConstInit(inits); - - // build the constant - // note that the type matches the initializer, not the aggregate in cases with unions - LLConstant* c = LLConstantStruct::get(inits, aggrdecl->ir.irStruct->packed); - Logger::cout() << "llvm constant: " << *c << '\n'; -// assert(0); - return c; -} diff -r 08f87d8cd101 -r 79758fd2f48a ir/irstruct.h --- a/ir/irstruct.h Mon Apr 13 17:42:36 2009 +0200 +++ b/ir/irstruct.h Wed Apr 15 20:06:25 2009 +0200 @@ -6,178 +6,110 @@ #include #include -struct IrInterface; +// DMD forward declarations +struct StructInitializer; -void addZeros(std::vector& inits, size_t pos, size_t offset); -void addZeros(std::vector& inits, size_t pos, size_t offset); -void addZeros(std::vector& inits, size_t pos, size_t offset); - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // represents a struct or class // it is used during codegen to hold all the vital info we need struct IrStruct : IrBase { - ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////// - - typedef std::vector VarDeclVector; - - typedef std::map InterfaceMap; - typedef InterfaceMap::iterator InterfaceMapIter; - - typedef std::vector InterfaceVector; - typedef InterfaceVector::iterator InterfaceVectorIter; - - // vector of LLVM types - typedef std::vector TypeVector; - - ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////// - - // Anon represents an anonymous struct union block inside an aggregate - // during LLVM type construction. - struct Anon - { - bool isunion; - Anon* parent; - - TypeVector types; - - Anon(bool IsUnion, Anon* par) : isunion(IsUnion), parent(par) {} - }; - - ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////// - - /// ctor + /// Constructor. IrStruct(AggregateDeclaration* agg); - /// dtor - virtual ~IrStruct(); - - ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////// - - /// push an anonymous struct/union - void pushAnon(bool isunion); - - /// pops an anonymous struct/union - void popAnon(); - - /// adds field - void addVar(VarDeclaration* var); + ////////////////////////////////////////////////////////////////////////// + // public fields, + // FIXME this is basically stuff I just haven't gotten around to yet. - ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////// - - /// build the aggr type - const LLType* build(); - - /// put the aggr initializers in a vector - void buildDefaultConstInit(std::vector& inits); - - /// ditto - but also builds the constant struct, for convenience - LLConstant* buildDefaultConstInit(); - - ///////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////// - - // the D aggregate + /// The D aggregate. AggregateDeclaration* aggrdecl; - // vector of VarDeclarations in this aggregate - VarDeclVector varDecls; - - // vector of VarDeclarations that contribute to the default initializer - VarDeclVector defVars; - - // true if the default initializer has been built - bool defaultFound; - - // top element - Anon* anon; - - // toplevel types in this aggr - TypeVector types; - - // current index - // always the same as types.size() - size_t index; - - // aggregate D type + /// Aggregate D type. Type* type; - // class vtable type - llvm::PATypeHolder vtblTy; - llvm::PATypeHolder vtblInitTy; + /// true only for: align(1) struct S { ... } + bool packed; + + /// Composite type debug description. + llvm::DICompositeType diCompositeType; + + ////////////////////////////////////////////////////////////////////////// - // initializer type opaque (type of global matches initializer, not formal type) - llvm::PATypeHolder initOpaque; - llvm::PATypeHolder classInfoOpaque; + /// Create the __initZ symbol lazily. + LLGlobalVariable* getInitSymbol(); + /// Builds the __initZ initializer constant lazily. + LLConstant* getDefaultInit(); + + /// Create the __vtblZ symbol lazily. + LLGlobalVariable* getVtblSymbol(); + /// Builds the __vtblZ initializer constant lazily. + LLConstant* getVtblInit(); - // map/vector of interfaces implemented - InterfaceMap interfaceMap; - InterfaceVector interfaceVec; + /// Create the __ClassZ symbol lazily. + LLGlobalVariable* getClassInfoSymbol(); + /// Builds the __ClassZ initializer constant lazily. + LLConstant* getClassInfoInit(); - // interface info array global - LLGlobalVariable* interfaceInfos; + /// Create the __interfaceInfos symbol lazily. + LLGlobalVariable* getInterfaceArraySymbol(); + + /// Creates a StructInitializer constant. + LLConstant* createStructInitializer(StructInitializer* si); - // ... - bool defined; - bool constinited; + ////////////////////////////////////////////////////////////////////////// +protected: + /// Static default initializer global. + llvm::GlobalVariable* init; + /// Static default initializer constant. + LLConstant* constInit; - // vtbl global and initializer - LLGlobalVariable* vtbl; + /// Vtbl global. + llvm::GlobalVariable* vtbl; + /// Vtbl initializer constant. LLConstant* constVtbl; - // static initializers global and constant - LLGlobalVariable* init; - LLConstant* constInit; - - // classinfo global and initializer constant - LLGlobalVariable* classInfo; + /// ClassInfo global. + llvm::GlobalVariable* classInfo; + /// ClassInfo initializer constant. LLConstant* constClassInfo; - bool classInfoDeclared; - bool classInfoDefined; - // vector of interfaces that should be put in ClassInfo.interfaces - InterfaceVector classInfoInterfaces; + + /// Map for mapping ClassDeclaration* to LLVM GlobalVariable. + typedef std::map ClassGlobalMap; + + /// Map from of interface vtbls implemented by this class. + ClassGlobalMap interfaceVtblMap; + + /// Interface info array global. + /// Basically: static object.Interface[num_interfaces] + llvm::GlobalVariable* classInterfacesArray; + + ////////////////////////////////////////////////////////////////////////// + + /// Create static default initializer for struct. + LLConstant* createStructDefaultInitializer(); - // align(1) struct S { ... } - bool packed; + /// Create static default initializer for class. + LLConstant* createClassDefaultInitializer(); + + /// Returns vtbl for interface implementation, creates it if not already built. + llvm::GlobalVariable* getInterfaceVtbl(BaseClass* b, bool new_inst); - // composite type debug description - llvm::DICompositeType diCompositeType; + /// Add base class data to initializer list. + /// Also creates the IrField instance for each data field. + void addBaseClassInits( + std::vector& constants, + ClassDeclaration* base, + size_t& offset, + size_t& field_index); - std::vector staticVars; - std::vector structFuncs; + // FIXME make this a member instead + friend LLConstant* DtoDefineClassInfo(ClassDeclaration* cd); + + /// Create the Interface[] interfaces ClassInfo field initializer. + LLConstant* getClassInfoInterfaces(); }; ////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -// represents interface implemented by a class -struct IrInterface : IrBase -{ - BaseClass* base; - ClassDeclaration* decl; - - llvm::PATypeHolder vtblInitTy; - - LLConstant* vtblInit; - LLGlobalVariable* vtbl; - Array vtblDecls; // array of FuncDecls that make up the vtbl - - const LLStructType* infoTy; - LLConstant* infoInit; - LLConstant* info; - - size_t index; - - IrInterface(BaseClass* b); -}; #endif diff -r 08f87d8cd101 -r 79758fd2f48a ir/irtype.cpp --- a/ir/irtype.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/ir/irtype.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -1,8 +1,16 @@ #include "llvm/DerivedTypes.h" +#include "mars.h" +#include "mtype.h" +#include "gen/irstate.h" +#include "gen/logger.h" #include "ir/irtype.h" -#include "mars.h" -#include "mtype.h" +////////////////////////////////////////////////////////////////////////////// + +extern const llvm::Type* DtoType(Type* dt); +extern const llvm::Type* DtoSize_t(); + +////////////////////////////////////////////////////////////////////////////// IrType::IrType(Type* dt, const llvm::Type* lt) : dtype(dt), @@ -10,6 +18,8 @@ { assert(dt && "null D Type"); assert(lt && "null LLVM Type"); + assert(dt->ir.type == NULL && "llvm type (old one) already set"); + dt->ir.type = &pa; } ////////////////////////////////////////////////////////////////////////////// @@ -23,6 +33,13 @@ ////////////////////////////////////////////////////////////////////////////// +const llvm::Type * IrTypeBasic::buildType() +{ + return pa.get(); +} + +////////////////////////////////////////////////////////////////////////////// + const llvm::Type * IrTypeBasic::basic2llvm(Type* t) { const llvm::Type* t2; @@ -101,19 +118,26 @@ ////////////////////////////////////////////////////////////////////////////// IrTypePointer::IrTypePointer(Type * dt) -: IrType(dt, pointer2llvm(dt)) +: IrType(dt, llvm::OpaqueType::get()) { } ////////////////////////////////////////////////////////////////////////////// -extern const llvm::Type* DtoType(Type* dt); - -const llvm::Type * IrTypePointer::pointer2llvm(Type * t) +const llvm::Type * IrTypePointer::buildType() { - assert(t->ty == Tpointer && "not pointer type"); + llvm::cast(pa.get())->refineAbstractTypeTo( + pointer2llvm(dtype)); + return pa.get(); +} - const llvm::Type* elemType = DtoType(t->nextOf()); +////////////////////////////////////////////////////////////////////////////// + +const llvm::Type * IrTypePointer::pointer2llvm(Type * dt) +{ + assert(dt->ty == Tpointer && "not pointer type"); + + const llvm::Type* elemType = DtoType(dt->nextOf()); if (elemType == llvm::Type::VoidTy) elemType = llvm::Type::Int8Ty; return llvm::PointerType::get(elemType, 0); @@ -124,21 +148,26 @@ ////////////////////////////////////////////////////////////////////////////// IrTypeSArray::IrTypeSArray(Type * dt) -: IrType(dt, sarray2llvm(dt)) +: IrType(dt, llvm::OpaqueType::get()) { + assert(dt->ty == Tsarray && "not static array type"); TypeSArray* tsa = (TypeSArray*)dt; - uint64_t d = (uint64_t)tsa->dim->toUInteger(); - assert(d == dim); + dim = (uint64_t)tsa->dim->toUInteger(); +} + +////////////////////////////////////////////////////////////////////////////// + +const llvm::Type * IrTypeSArray::buildType() +{ + llvm::cast(pa.get())->refineAbstractTypeTo( + sarray2llvm(dtype)); + return pa.get(); } ////////////////////////////////////////////////////////////////////////////// const llvm::Type * IrTypeSArray::sarray2llvm(Type * t) { - assert(t->ty == Tsarray && "not static array type"); - - TypeSArray* tsa = (TypeSArray*)t; - dim = (uint64_t)tsa->dim->toUInteger(); const llvm::Type* elemType = DtoType(t->nextOf()); if (elemType == llvm::Type::VoidTy) elemType = llvm::Type::Int8Ty; @@ -150,23 +179,38 @@ ////////////////////////////////////////////////////////////////////////////// IrTypeArray::IrTypeArray(Type * dt) -: IrType(dt, array2llvm(dt)) +: IrType(dt, llvm::OpaqueType::get()) { } ////////////////////////////////////////////////////////////////////////////// -extern const llvm::Type* DtoSize_t(); +const llvm::Type * IrTypeArray::buildType() +{ + llvm::cast(pa.get())->refineAbstractTypeTo( + array2llvm(dtype)); + return pa.get(); +} + +////////////////////////////////////////////////////////////////////////////// const llvm::Type * IrTypeArray::array2llvm(Type * t) { assert(t->ty == Tarray && "not dynamic array type"); + // get .ptr type const llvm::Type* elemType = DtoType(t->nextOf()); if (elemType == llvm::Type::VoidTy) elemType = llvm::Type::Int8Ty; elemType = llvm::PointerType::get(elemType, 0); - return llvm::StructType::get(DtoSize_t(), elemType, NULL); + + // create struct type + const llvm::Type* at = llvm::StructType::get(DtoSize_t(), elemType, NULL); + + // name dynamic array types + Type::sir->getState()->module->addTypeName(t->toChars(), at); + + return at; } ////////////////////////////////////////////////////////////////////////////// diff -r 08f87d8cd101 -r 79758fd2f48a ir/irtype.h --- a/ir/irtype.h Mon Apr 13 17:42:36 2009 +0200 +++ b/ir/irtype.h Wed Apr 15 20:06:25 2009 +0200 @@ -9,10 +9,13 @@ struct Type; +class IrTypeAggr; class IrTypeArray; class IrTypeBasic; +class IrTypeClass; class IrTypePointer; class IrTypeSArray; +class IrTypeStruct; ////////////////////////////////////////////////////////////////////////////// @@ -24,19 +27,29 @@ IrType(Type* dt, const llvm::Type* lt); /// - Type* getD() { return dtype; } - - /// - const llvm::Type* get() { return pa.get(); } - + virtual IrTypeAggr* isAggr() { return NULL; } /// virtual IrTypeArray* isArray() { return NULL; } /// virtual IrTypeBasic* isBasic() { return NULL; } /// + virtual IrTypeClass* isClass() { return NULL; } + /// virtual IrTypePointer* isPointer() { return NULL; } /// virtual IrTypeSArray* isSArray() { return NULL; } + /// + virtual IrTypeStruct* isStruct() { return NULL; } + + /// + Type* getD() { return dtype; } + /// + virtual const llvm::Type* get() { return pa.get(); } + /// + llvm::PATypeHolder& getPA() { return pa; } + + /// + virtual const llvm::Type* buildType() = 0; protected: /// @@ -58,6 +71,9 @@ /// IrTypeBasic* isBasic() { return this; } + /// + const llvm::Type* buildType(); + protected: /// const llvm::Type* basic2llvm(Type* t); @@ -75,6 +91,9 @@ /// IrTypePointer* isPointer() { return this; } + /// + const llvm::Type* buildType(); + protected: /// const llvm::Type* pointer2llvm(Type* t); @@ -92,6 +111,9 @@ /// IrTypeSArray* isSArray() { return this; } + /// + const llvm::Type* buildType(); + protected: /// const llvm::Type* sarray2llvm(Type* t); @@ -112,6 +134,9 @@ /// IrTypeArray* isArray() { return this; } + /// + const llvm::Type* buildType(); + protected: /// const llvm::Type* array2llvm(Type* t); diff -r 08f87d8cd101 -r 79758fd2f48a ir/irtypeclass.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ir/irtypeclass.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -0,0 +1,236 @@ +#include "llvm/DerivedTypes.h" + +#include "aggregate.h" +#include "declaration.h" +#include "dsymbol.h" +#include "mtype.h" + +#include "gen/irstate.h" +#include "gen/logger.h" +#include "gen/tollvm.h" +#include "gen/utils.h" +#include "ir/irtypeclass.h" + +////////////////////////////////////////////////////////////////////////////// + +extern size_t add_zeros(std::vector& defaultTypes, size_t diff); + +////////////////////////////////////////////////////////////////////////////// + +IrTypeClass::IrTypeClass(ClassDeclaration* cd) +: IrTypeAggr(cd), + cd(cd), + tc((TypeClass*)cd->type), + vtbl_pa(llvm::OpaqueType::get()) +{ + vtbl_size = cd->vtbl.dim; +} + +////////////////////////////////////////////////////////////////////////////// + +void IrTypeClass::addBaseClassData( + std::vector< const llvm::Type * > & defaultTypes, + ClassDeclaration * base, + size_t & offset, + size_t & field_index) +{ + if (base->baseClass) + { + addBaseClassData(defaultTypes, base->baseClass, offset, field_index); + } + + ArrayIter it(base->fields); + for (; !it.done(); it.next()) + { + VarDeclaration* vd = it.get(); + + // skip if offset moved backwards + if (vd->offset < offset) + { + IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset); + if (vd->ir.irField == NULL) + { + new IrField(vd, 2, vd->offset - PTRSIZE * 2); + } + continue; + } + + IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); + + // get next aligned offset for this type + size_t alignsize = vd->type->alignsize(); + size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); + + // do we need to insert explicit padding before the field? + if (alignedoffset < vd->offset) + { + field_index += add_zeros(defaultTypes, vd->offset - alignedoffset); + } + + // add default type + defaultTypes.push_back(DtoType(vd->type)); + + // advance offset to right past this field + offset = vd->offset + vd->type->size(); + + // give field index + // the IrField creation doesn't really belong here, but it's a trivial operation + // and it save yet another of these loops. + IF_LOG Logger::println("Field index: %zu", field_index); + if (vd->ir.irField == NULL) + { + new IrField(vd, field_index); + } + field_index++; + } + + // any interface implementations? + if (base->vtblInterfaces) + { + bool new_instances = (base == cd); + + ArrayIter it2(*base->vtblInterfaces); + + for (; !it2.done(); it2.next()) + { + BaseClass* b = it2.get(); + IF_LOG Logger::println("Adding interface vtbl for %s", b->base->toPrettyChars()); + + Array arr; + b->fillVtbl(cd, &arr, new_instances); + + const llvm::Type* ivtbl_type = buildVtblType(Type::tvoid->pointerTo(), &arr); + defaultTypes.push_back(llvm::PointerType::get(ivtbl_type, 0)); + + offset += PTRSIZE; + + // add to the interface map + if (interfaceMap.find(b->base) == interfaceMap.end()) + interfaceMap.insert(std::make_pair(b->base, field_index)); + field_index++; + } + } + + // tail padding? + if (offset < base->structsize) + { + field_index += add_zeros(defaultTypes, base->structsize - offset); + offset = base->structsize; + } +} + +////////////////////////////////////////////////////////////////////////////// + +const llvm::Type* IrTypeClass::buildType() +{ + IF_LOG Logger::println("Building class type %s @ %s", cd->toPrettyChars(), cd->locToChars()); + LOG_SCOPE; + IF_LOG Logger::println("Instance size: %u", cd->structsize); + + // find the fields that contribute to the default initializer. + // these will define the default type. + + std::vector defaultTypes; + defaultTypes.reserve(32); + + // add vtbl + defaultTypes.push_back(llvm::PointerType::get(vtbl_pa.get(), 0)); + + // interface are just a vtable + if (!cd->isInterfaceDeclaration()) + { + // add monitor + defaultTypes.push_back(llvm::PointerType::get(llvm::Type::Int8Ty, 0)); + + // we start right after the vtbl and monitor + size_t offset = PTRSIZE * 2; + size_t field_index = 2; + + // add data members recursively + addBaseClassData(defaultTypes, cd, offset, field_index); + } + + // errors are fatal during codegen + if (global.errors) + fatal(); + + // build the llvm type + const llvm::Type* st = llvm::StructType::get(defaultTypes, false); + + // refine type + llvm::cast(pa.get())->refineAbstractTypeTo(st); + + // name type + Type::sir->getState()->module->addTypeName(cd->toPrettyChars(), pa.get()); + + // VTBL + + // build vtbl type + const llvm::Type* vtblty = buildVtblType( + ClassDeclaration::classinfo->type, + &cd->vtbl); + + // refine vtbl pa + llvm::cast(vtbl_pa.get())->refineAbstractTypeTo(vtblty); + + // name vtbl type + std::string name(cd->toPrettyChars()); + name.append(".__vtbl"); + Type::sir->getState()->module->addTypeName(name, vtbl_pa.get()); + +#if 0 + IF_LOG Logger::cout() << "class type: " << *pa.get() << std::endl; +#endif + + return get(); +} + +////////////////////////////////////////////////////////////////////////////// + +const llvm::Type* IrTypeClass::buildVtblType(Type* first, Array* vtbl_array) +{ + IF_LOG Logger::println("Building vtbl type for class %s", cd->toPrettyChars()); + LOG_SCOPE; + + std::vector types; + types.reserve(vtbl_array->dim); + + // first comes the classinfo + types.push_back(DtoType(first)); + + // then come the functions + ArrayIter it(*vtbl_array); + it.index = 1; + + for (; !it.done(); it.next()) + { + FuncDeclaration* fd = it.get()->isFuncDeclaration(); + assert(fd && "invalid vtbl entry"); + + IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); + + types.push_back(DtoType(fd->type->pointerTo())); + } + + // build the vtbl llvm type + return llvm::StructType::get(types, false); +} + +////////////////////////////////////////////////////////////////////////////// + +const llvm::Type * IrTypeClass::get() +{ + return llvm::PointerType::get(pa.get(), 0); +} + +////////////////////////////////////////////////////////////////////////////// + +size_t IrTypeClass::getInterfaceIndex(ClassDeclaration * inter) +{ + ClassIndexMap::iterator it = interfaceMap.find(inter); + if (it == interfaceMap.end()) + return ~0; + return it->second; +} + +////////////////////////////////////////////////////////////////////////////// diff -r 08f87d8cd101 -r 79758fd2f48a ir/irtypeclass.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ir/irtypeclass.h Wed Apr 15 20:06:25 2009 +0200 @@ -0,0 +1,65 @@ +#ifndef __LDC_IR_IRTYPECLASS_H__ +#define __LDC_IR_IRTYPECLASS_H__ + +#include "ir/irtypestruct.h" + +/// +class IrTypeClass : public IrTypeAggr +{ +public: + /// + IrTypeClass(ClassDeclaration* cd); + + /// + virtual IrTypeClass* isClass() { return this; } + + /// + const llvm::Type* buildType(); + + /// + const llvm::Type* getVtbl() { return vtbl_pa.get(); } + + /// + const llvm::Type* get(); + + /// Get index to interface implementation. + /// Returns the index of a specific interface implementation in this + /// class or ~0 if not found. + size_t getInterfaceIndex(ClassDeclaration* inter); + + /// Returns the total number of pointers in the vtable. + unsigned getVtblSize() { return vtbl_size; } + +protected: + /// + ClassDeclaration* cd; + /// + TypeClass* tc; + + /// + llvm::PATypeHolder vtbl_pa; + + /// Number of pointers in vtable. + unsigned vtbl_size; + + /// std::map type mapping ClassDeclaration* to size_t. + typedef std::map ClassIndexMap; + + /// Map for mapping the index of a specific interface implementation + /// in this class to it's ClassDeclaration*. + ClassIndexMap interfaceMap; + + ////////////////////////////////////////////////////////////////////////// + + /// + const llvm::Type* buildVtblType(Type* first, Array* vtbl_array); + + /// + void addBaseClassData( + std::vector& defaultTypes, + ClassDeclaration* base, + size_t& offset, + size_t& field_index); +}; + +#endif diff -r 08f87d8cd101 -r 79758fd2f48a ir/irtypestruct.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ir/irtypestruct.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -0,0 +1,148 @@ +#include "llvm/DerivedTypes.h" + +#include "aggregate.h" +#include "declaration.h" +#include "mtype.h" + +#include "gen/irstate.h" +#include "gen/tollvm.h" +#include "gen/logger.h" +#include "gen/utils.h" +#include "ir/irtypestruct.h" + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +IrTypeAggr::IrTypeAggr(AggregateDeclaration * ad) +: IrType(ad->type, llvm::OpaqueType::get()), + aggr(ad) +{ +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +IrTypeStruct::IrTypeStruct(StructDeclaration * sd) +: IrTypeAggr(sd), + sd(sd), + ts((TypeStruct*)sd->type) +{ +} + +////////////////////////////////////////////////////////////////////////////// + +size_t add_zeros(std::vector& defaultTypes, size_t diff) +{ + size_t n = defaultTypes.size(); + while (diff) + { + if (global.params.is64bit && diff % 8 == 0) + { + defaultTypes.push_back(llvm::Type::Int64Ty); + diff -= 8; + } + else if (diff % 4 == 0) + { + defaultTypes.push_back(llvm::Type::Int32Ty); + diff -= 4; + } + else if (diff % 2 == 0) + { + defaultTypes.push_back(llvm::Type::Int16Ty); + diff -= 2; + } + else + { + defaultTypes.push_back(llvm::Type::Int8Ty); + diff -= 1; + } + } + return defaultTypes.size() - n; +} + +const llvm::Type* IrTypeStruct::buildType() +{ + IF_LOG Logger::println("Building struct type %s @ %s", sd->toPrettyChars(), sd->locToChars()); + LOG_SCOPE; + + // find the fields that contribute to the default initializer. + // these will define the default type. + + std::vector defaultTypes; + defaultTypes.reserve(16); + + size_t offset = 0; + size_t field_index = 0; + + bool packed = (sd->type->alignsize() == 1); + + ArrayIter it(sd->fields); + for (; !it.done(); it.next()) + { + VarDeclaration* vd = it.get(); + + assert(vd->ir.irField == NULL && "struct inheritance is not allowed, how can this happen?"); + + // skip if offset moved backwards + if (vd->offset < offset) + { + IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset); + new IrField(vd, 0, vd->offset); + continue; + } + + IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); + + // get next aligned offset for this type + size_t alignedoffset = offset; + if (!packed) + { + size_t alignsize = vd->type->alignsize(); + alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); + } + + // insert explicit padding? + if (alignedoffset < vd->offset) + { + field_index += add_zeros(defaultTypes, vd->offset - alignedoffset); + } + + // add default type + defaultTypes.push_back(DtoType(vd->type)); + + // advance offset to right past this field + offset = vd->offset + vd->type->size(); + + // give field index + // the IrField creation doesn't really belong here, but it's a trivial operation + // and it save yet another of these loops. + IF_LOG Logger::println("Field index: %zu", field_index); + new IrField(vd, field_index); + field_index++; + } + + // tail padding? + if (offset < sd->structsize) + { + add_zeros(defaultTypes, sd->structsize - offset); + } + + // build the llvm type + const llvm::Type* st = llvm::StructType::get(defaultTypes, packed); + + // refine type + llvm::cast(pa.get())->refineAbstractTypeTo(st); + + // name types + Type::sir->getState()->module->addTypeName(sd->toPrettyChars(), pa.get()); + +#if 0 + IF_LOG Logger::cout() << "struct type: " << *pa.get() << std::endl; +#endif + + return pa.get(); +} + +////////////////////////////////////////////////////////////////////////////// diff -r 08f87d8cd101 -r 79758fd2f48a ir/irtypestruct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ir/irtypestruct.h Wed Apr 15 20:06:25 2009 +0200 @@ -0,0 +1,52 @@ +#ifndef __LDC_IR_IRTYPESTRUCT_H__ +#define __LDC_IR_IRTYPESTRUCT_H__ + +#include "ir/irtype.h" + +////////////////////////////////////////////////////////////////////////////// + +struct AggregateDeclaration; +struct StructDeclaration; +struct TypeStruct; + +////////////////////////////////////////////////////////////////////////////// + +class IrTypeAggr : public IrType +{ +public: + /// + IrTypeAggr(AggregateDeclaration* ad); + + /// + IrTypeAggr* isAggr() { return this; } + +protected: + /// AggregateDeclaration this type represents. + AggregateDeclaration* aggr; +}; + +////////////////////////////////////////////////////////////////////////////// + +class IrTypeStruct : public IrTypeAggr +{ +public: + /// + IrTypeStruct(StructDeclaration* sd); + + /// + IrTypeStruct* isStruct() { return this; } + + /// + const llvm::Type* buildType(); + +protected: + /// StructDeclaration this type represents. + StructDeclaration* sd; + + /// DMD TypeStruct of this type. + TypeStruct* ts; +}; + +////////////////////////////////////////////////////////////////////////////// + +#endif diff -r 08f87d8cd101 -r 79758fd2f48a ir/irvar.cpp --- a/ir/irvar.cpp Mon Apr 13 17:42:36 2009 +0200 +++ b/ir/irvar.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -36,11 +36,14 @@ ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -IrField::IrField(VarDeclaration* v) : IrVar(v) +IrField::IrField(VarDeclaration* v, size_t idx, size_t offset) : IrVar(v) { - index = 0; - unionOffset = 0; + index = idx; + unionOffset = offset; constInit = NULL; + + assert(V->ir.irField == NULL && "field for this variable already exists"); + V->ir.irField = this; } ////////////////////////////////////////////////////////////////////////////// diff -r 08f87d8cd101 -r 79758fd2f48a ir/irvar.h --- a/ir/irvar.h Mon Apr 13 17:42:36 2009 +0200 +++ b/ir/irvar.h Wed Apr 15 20:06:25 2009 +0200 @@ -34,11 +34,12 @@ // represents an aggregate field variable struct IrField : IrVar { - IrField(VarDeclaration* v); + IrField(VarDeclaration* v, size_t idx, size_t offset = 0); unsigned index; unsigned unionOffset; +protected: llvm::Constant* constInit; };