diff options
Diffstat (limited to 'clang/lib/Basic')
-rw-r--r-- | clang/lib/Basic/Diagnostic.cpp | 232 | ||||
-rw-r--r-- | clang/lib/Basic/FileManager.cpp | 275 | ||||
-rw-r--r-- | clang/lib/Basic/IdentifierTable.cpp | 551 | ||||
-rw-r--r-- | clang/lib/Basic/LangOptions.cpp | 58 | ||||
-rw-r--r-- | clang/lib/Basic/Makefile | 22 | ||||
-rw-r--r-- | clang/lib/Basic/SourceLocation.cpp | 79 | ||||
-rw-r--r-- | clang/lib/Basic/SourceManager.cpp | 574 | ||||
-rw-r--r-- | clang/lib/Basic/TargetInfo.cpp | 210 | ||||
-rw-r--r-- | clang/lib/Basic/Targets.cpp | 757 | ||||
-rw-r--r-- | clang/lib/Basic/TokenKinds.cpp | 29 |
10 files changed, 2787 insertions, 0 deletions
diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp new file mode 100644 index 00000000000..f62b8f126cd --- /dev/null +++ b/clang/lib/Basic/Diagnostic.cpp @@ -0,0 +1,232 @@ +//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Diagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include <cassert> +#include <vector> +#include <map> +#include <cstring> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Builtin Diagnostic information +//===----------------------------------------------------------------------===// + +/// Flag values for diagnostics. +enum { + // Diagnostic classes. + NOTE = 0x01, + WARNING = 0x02, + EXTENSION = 0x03, + ERROR = 0x04, + class_mask = 0x07 +}; + +/// DiagnosticFlags - A set of flags, or'd together, that describe the +/// diagnostic. +static unsigned char DiagnosticFlags[] = { +#define DIAG(ENUM,FLAGS,DESC) FLAGS, +#include "clang/Basic/DiagnosticKinds.def" + 0 +}; + +/// getDiagClass - Return the class field of the diagnostic. +/// +static unsigned getBuiltinDiagClass(unsigned DiagID) { + assert(DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && + "Diagnostic ID out of range!"); + return DiagnosticFlags[DiagID] & class_mask; +} + +/// DiagnosticText - An english message to print for the diagnostic. These +/// should be localized. +static const char * const DiagnosticText[] = { +#define DIAG(ENUM,FLAGS,DESC) DESC, +#include "clang/Basic/DiagnosticKinds.def" + 0 +}; + +//===----------------------------------------------------------------------===// +// Custom Diagnostic information +//===----------------------------------------------------------------------===// + +namespace clang { + namespace diag { + class CustomDiagInfo { + typedef std::pair<Diagnostic::Level, std::string> DiagDesc; + std::vector<DiagDesc> DiagInfo; + std::map<DiagDesc, unsigned> DiagIDs; + public: + + /// getDescription - Return the description of the specified custom + /// diagnostic. + const char *getDescription(unsigned DiagID) const { + assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && + "Invalid diagnosic ID"); + return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].second.c_str(); + } + + /// getLevel - Return the level of the specified custom diagnostic. + Diagnostic::Level getLevel(unsigned DiagID) const { + assert(this && DiagID-diag::NUM_BUILTIN_DIAGNOSTICS < DiagInfo.size() && + "Invalid diagnosic ID"); + return DiagInfo[DiagID-diag::NUM_BUILTIN_DIAGNOSTICS].first; + } + + unsigned getOrCreateDiagID(Diagnostic::Level L, const char *Message) { + DiagDesc D(L, Message); + // Check to see if it already exists. + std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D); + if (I != DiagIDs.end() && I->first == D) + return I->second; + + // If not, assign a new ID. + unsigned ID = DiagInfo.size()+diag::NUM_BUILTIN_DIAGNOSTICS; + DiagIDs.insert(std::make_pair(D, ID)); + DiagInfo.push_back(D); + return ID; + } + }; + + } // end diag namespace +} // end clang namespace + + +//===----------------------------------------------------------------------===// +// Common Diagnostic implementation +//===----------------------------------------------------------------------===// + +Diagnostic::Diagnostic(DiagnosticClient &client) : Client(client) { + WarningsAsErrors = false; + WarnOnExtensions = false; + ErrorOnExtensions = false; + // Clear all mappings, setting them to MAP_DEFAULT. + memset(DiagMappings, 0, sizeof(DiagMappings)); + + ErrorOccurred = false; + NumDiagnostics = 0; + NumErrors = 0; + CustomDiagInfo = 0; +} + +Diagnostic::~Diagnostic() { + delete CustomDiagInfo; +} + +/// getCustomDiagID - Return an ID for a diagnostic with the specified message +/// and level. If this is the first request for this diagnosic, it is +/// registered and created, otherwise the existing ID is returned. +unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) { + if (CustomDiagInfo == 0) + CustomDiagInfo = new diag::CustomDiagInfo(); + return CustomDiagInfo->getOrCreateDiagID(L, Message); +} + + +/// isBuiltinNoteWarningOrExtension - Return true if the unmapped diagnostic +/// level of the specified diagnostic ID is a Note, Warning, or Extension. +/// Note that this only works on builtin diagnostics, not custom ones. +bool Diagnostic::isBuiltinNoteWarningOrExtension(unsigned DiagID) { + return DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && + getBuiltinDiagClass(DiagID) < ERROR; +} + + +/// getDescription - Given a diagnostic ID, return a description of the +/// issue. +const char *Diagnostic::getDescription(unsigned DiagID) { + if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS) + return DiagnosticText[DiagID]; + else + return CustomDiagInfo->getDescription(DiagID); +} + +/// getDiagnosticLevel - Based on the way the client configured the Diagnostic +/// object, classify the specified diagnostic ID into a Level, consumable by +/// the DiagnosticClient. +Diagnostic::Level Diagnostic::getDiagnosticLevel(unsigned DiagID) const { + // Handle custom diagnostics, which cannot be mapped. + if (DiagID >= diag::NUM_BUILTIN_DIAGNOSTICS) + return CustomDiagInfo->getLevel(DiagID); + + unsigned DiagClass = getBuiltinDiagClass(DiagID); + + // Specific non-error diagnostics may be mapped to various levels from ignored + // to error. + if (DiagClass < ERROR) { + switch (getDiagnosticMapping((diag::kind)DiagID)) { + case diag::MAP_DEFAULT: break; + case diag::MAP_IGNORE: return Ignored; + case diag::MAP_WARNING: DiagClass = WARNING; break; + case diag::MAP_ERROR: DiagClass = ERROR; break; + } + } + + // Map diagnostic classes based on command line argument settings. + if (DiagClass == EXTENSION) { + if (ErrorOnExtensions) + DiagClass = ERROR; + else if (WarnOnExtensions) + DiagClass = WARNING; + else + return Ignored; + } + + // If warnings are to be treated as errors, indicate this as such. + if (DiagClass == WARNING && WarningsAsErrors) + DiagClass = ERROR; + + switch (DiagClass) { + default: assert(0 && "Unknown diagnostic class!"); + case NOTE: return Diagnostic::Note; + case WARNING: return Diagnostic::Warning; + case ERROR: return Diagnostic::Error; + } +} + +/// Report - Issue the message to the client. If the client wants us to stop +/// compilation, return true, otherwise return false. DiagID is a member of +/// the diag::kind enum. +void Diagnostic::Report(FullSourceLoc Pos, unsigned DiagID, + const std::string *Strs, unsigned NumStrs, + const SourceRange *Ranges, unsigned NumRanges) { + + // Figure out the diagnostic level of this message. + Diagnostic::Level DiagLevel = getDiagnosticLevel(DiagID); + + // If the client doesn't care about this message, don't issue it. + if (DiagLevel == Diagnostic::Ignored) + return; + + // If this is not an error and we are in a system header, ignore it. We have + // to check on the original class here, because we also want to ignore + // extensions and warnings in -Werror and -pedantic-errors modes, which *map* + // warnings/extensions to errors. + if (DiagID < diag::NUM_BUILTIN_DIAGNOSTICS && + getBuiltinDiagClass(DiagID) != ERROR && + Client.isInSystemHeader(Pos)) + return; + + if (DiagLevel >= Diagnostic::Error) { + ErrorOccurred = true; + ++NumErrors; + } + + // Finally, report it. + Client.HandleDiagnostic(*this, DiagLevel, Pos, (diag::kind)DiagID, + Strs, NumStrs, Ranges, NumRanges); + ++NumDiagnostics; +} + +DiagnosticClient::~DiagnosticClient() {} diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp new file mode 100644 index 00000000000..cfc08ed084b --- /dev/null +++ b/clang/lib/Basic/FileManager.cpp @@ -0,0 +1,275 @@ +///===--- FileManager.cpp - File System Probing and Caching ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the FileManager interface. +// +//===----------------------------------------------------------------------===// +// +// TODO: This should index all interesting directories with dirent calls. +// getdirentries ? +// opendir/readdir_r/closedir ? +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/FileManager.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" +#include "llvm/Support/Streams.h" +#include "llvm/Config/config.h" +using namespace clang; + +// FIXME: Enhance libsystem to support inode and other fields. +#include <sys/stat.h> + +#if defined(_MSC_VER) +#define S_ISDIR(s) (_S_IFDIR & s) +#endif + +/// NON_EXISTENT_DIR - A special value distinct from null that is used to +/// represent a dir name that doesn't exist on the disk. +#define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1) + +#ifdef LLVM_ON_WIN32 + +#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\') + +namespace { + static std::string GetFullPath(const char *relPath) + { + char *absPathStrPtr = _fullpath(NULL, relPath, 0); + assert(absPathStrPtr && "_fullpath() returned NULL!"); + + std::string absPath(absPathStrPtr); + + free(absPathStrPtr); + return absPath; + } +} + +class FileManager::UniqueDirContainer { + /// UniqueDirs - Cache from full path to existing directories/files. + /// + llvm::StringMap<DirectoryEntry> UniqueDirs; + +public: + DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { + std::string FullPath(GetFullPath(Name)); + return UniqueDirs.GetOrCreateValue( + FullPath.c_str(), + FullPath.c_str() + FullPath.size() + ).getValue(); + } + + size_t size() { return UniqueDirs.size(); } +}; + +class FileManager::UniqueFileContainer { + /// UniqueFiles - Cache from full path to existing directories/files. + /// + llvm::StringMap<FileEntry> UniqueFiles; + +public: + FileEntry &getFile(const char *Name, struct stat &StatBuf) { + std::string FullPath(GetFullPath(Name)); + return UniqueFiles.GetOrCreateValue( + FullPath.c_str(), + FullPath.c_str() + FullPath.size() + ).getValue(); + } + + size_t size() { return UniqueFiles.size(); } +}; + +#else + +#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/') + +class FileManager::UniqueDirContainer { + /// UniqueDirs - Cache from ID's to existing directories/files. + /// + std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs; + +public: + DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { + return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)]; + } + + size_t size() { return UniqueDirs.size(); } +}; + +class FileManager::UniqueFileContainer { + /// UniqueFiles - Cache from ID's to existing directories/files. + /// + std::set<FileEntry> UniqueFiles; + +public: + FileEntry &getFile(const char *Name, struct stat &StatBuf) { + return + const_cast<FileEntry&>( + *UniqueFiles.insert(FileEntry(StatBuf.st_dev, + StatBuf.st_ino)).first); + } + + size_t size() { return UniqueFiles.size(); } +}; + +#endif + + +FileManager::FileManager() : UniqueDirs(*new UniqueDirContainer), + UniqueFiles(*new UniqueFileContainer), + DirEntries(64), FileEntries(64), NextFileUID(0) +{ + NumDirLookups = NumFileLookups = 0; + NumDirCacheMisses = NumFileCacheMisses = 0; +} + +FileManager::~FileManager() { + delete &UniqueDirs; + delete &UniqueFiles; +} + + +/// getDirectory - Lookup, cache, and verify the specified directory. This +/// returns null if the directory doesn't exist. +/// +const DirectoryEntry *FileManager::getDirectory(const char *NameStart, + const char *NameEnd) { + ++NumDirLookups; + llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt = + DirEntries.GetOrCreateValue(NameStart, NameEnd); + + // See if there is already an entry in the map. + if (NamedDirEnt.getValue()) + return NamedDirEnt.getValue() == NON_EXISTENT_DIR + ? 0 : NamedDirEnt.getValue(); + + ++NumDirCacheMisses; + + // By default, initialize it to invalid. + NamedDirEnt.setValue(NON_EXISTENT_DIR); + + // Get the null-terminated directory name as stored as the key of the + // DirEntries map. + const char *InterndDirName = NamedDirEnt.getKeyData(); + + // Check to see if the directory exists. + struct stat StatBuf; + if (stat(InterndDirName, &StatBuf) || // Error stat'ing. + !S_ISDIR(StatBuf.st_mode)) // Not a directory? + return 0; + + // It exists. See if we have already opened a directory with the same inode. + // This occurs when one dir is symlinked to another, for example. + DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf); + + NamedDirEnt.setValue(&UDE); + if (UDE.getName()) // Already have an entry with this inode, return it. + return &UDE; + + // Otherwise, we don't have this directory yet, add it. We use the string + // key from the DirEntries map as the string. + UDE.Name = InterndDirName; + return &UDE; +} + +/// NON_EXISTENT_FILE - A special value distinct from null that is used to +/// represent a filename that doesn't exist on the disk. +#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1) + +/// getFile - Lookup, cache, and verify the specified file. This returns null +/// if the file doesn't exist. +/// +const FileEntry *FileManager::getFile(const char *NameStart, + const char *NameEnd) { + ++NumFileLookups; + + // See if there is already an entry in the map. + llvm::StringMapEntry<FileEntry *> &NamedFileEnt = + FileEntries.GetOrCreateValue(NameStart, NameEnd); + + // See if there is already an entry in the map. + if (NamedFileEnt.getValue()) + return NamedFileEnt.getValue() == NON_EXISTENT_FILE + ? 0 : NamedFileEnt.getValue(); + + ++NumFileCacheMisses; + + // By default, initialize it to invalid. + NamedFileEnt.setValue(NON_EXISTENT_FILE); + + // Figure out what directory it is in. If the string contains a / in it, + // strip off everything after it. + // FIXME: this logic should be in sys::Path. + const char *SlashPos = NameEnd-1; + while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0])) + --SlashPos; + + const DirectoryEntry *DirInfo; + if (SlashPos < NameStart) { + // Use the current directory if file has no path component. + const char *Name = "."; + DirInfo = getDirectory(Name, Name+1); + } else if (SlashPos == NameEnd-1) + return 0; // If filename ends with a /, it's a directory. + else + DirInfo = getDirectory(NameStart, SlashPos); + + if (DirInfo == 0) // Directory doesn't exist, file can't exist. + return 0; + + // Get the null-terminated file name as stored as the key of the + // FileEntries map. + const char *InterndFileName = NamedFileEnt.getKeyData(); + + // FIXME: Use the directory info to prune this, before doing the stat syscall. + // FIXME: This will reduce the # syscalls. + + // Nope, there isn't. Check to see if the file exists. + struct stat StatBuf; + //llvm::cerr << "STATING: " << Filename; + if (stat(InterndFileName, &StatBuf) || // Error stat'ing. + S_ISDIR(StatBuf.st_mode)) { // A directory? + // If this file doesn't exist, we leave a null in FileEntries for this path. + //llvm::cerr << ": Not existing\n"; + return 0; + } + //llvm::cerr << ": exists\n"; + + // It exists. See if we have already opened a file with the same inode. + // This occurs when one dir is symlinked to another, for example. + FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf); + + NamedFileEnt.setValue(&UFE); + if (UFE.getName()) // Already have an entry with this inode, return it. + return &UFE; + + // Otherwise, we don't have this directory yet, add it. + // FIXME: Change the name to be a char* that points back to the 'FileEntries' + // key. + UFE.Name = InterndFileName; + UFE.Size = StatBuf.st_size; + UFE.ModTime = StatBuf.st_mtime; + UFE.Dir = DirInfo; + UFE.UID = NextFileUID++; + return &UFE; +} + +void FileManager::PrintStats() const { + llvm::cerr << "\n*** File Manager Stats:\n"; + llvm::cerr << UniqueFiles.size() << " files found, " + << UniqueDirs.size() << " dirs found.\n"; + llvm::cerr << NumDirLookups << " dir lookups, " + << NumDirCacheMisses << " dir cache misses.\n"; + llvm::cerr << NumFileLookups << " file lookups, " + << NumFileCacheMisses << " file cache misses.\n"; + + //llvm::cerr << PagesMapped << BytesOfPagesMapped << FSLookups; +} diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp new file mode 100644 index 00000000000..65e984a0f78 --- /dev/null +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -0,0 +1,551 @@ +//===--- IdentifierTable.cpp - Hash table for identifier lookup -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the IdentifierInfo, IdentifierVisitor, and +// IdentifierTable interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// IdentifierInfo Implementation +//===----------------------------------------------------------------------===// + +IdentifierInfo::IdentifierInfo() { + TokenID = tok::identifier; + ObjCID = tok::objc_not_keyword; + BuiltinID = 0; + HasMacro = false; + IsExtension = false; + IsPoisoned = false; + IsCPPOperatorKeyword = false; + FETokenInfo = 0; +} + +//===----------------------------------------------------------------------===// +// IdentifierTable Implementation +//===----------------------------------------------------------------------===// + +IdentifierTable::IdentifierTable(const LangOptions &LangOpts) + // Start with space for 8K identifiers. + : HashTable(8192) { + + // Populate the identifier table with info about keywords for the current + // language. + AddKeywords(LangOpts); +} + +// This cstor is intended to be used only for serialization. +IdentifierTable::IdentifierTable() : HashTable(8192) {} + +//===----------------------------------------------------------------------===// +// Language Keyword Implementation +//===----------------------------------------------------------------------===// + +/// AddKeyword - This method is used to associate a token ID with specific +/// identifiers because they are language keywords. This causes the lexer to +/// automatically map matching identifiers to specialized token codes. +/// +/// The C90/C99/CPP/CPP0x flags are set to 0 if the token should be +/// enabled in the specified langauge, set to 1 if it is an extension +/// in the specified language, and set to 2 if disabled in the +/// specified language. +static void AddKeyword(const char *Keyword, unsigned KWLen, + tok::TokenKind TokenCode, + int C90, int C99, int CXX, int CXX0x, int BoolSupport, + const LangOptions &LangOpts, IdentifierTable &Table) { + int Flags = 0; + if (BoolSupport != 0) { + Flags = LangOpts.Boolean ? BoolSupport : 2; + } else if (LangOpts.CPlusPlus) { + Flags = LangOpts.CPlusPlus0x ? CXX0x : CXX; + } else if (LangOpts.C99) { + Flags = C99; + } else { + Flags = C90; + } + + // Don't add this keyword if disabled in this language or if an extension + // and extensions are disabled. + if (Flags + LangOpts.NoExtensions >= 2) return; + + IdentifierInfo &Info = Table.get(Keyword, Keyword+KWLen); + Info.setTokenID(TokenCode); + Info.setIsExtensionToken(Flags == 1); +} + +static void AddAlias(const char *Keyword, unsigned KWLen, + tok::TokenKind AliaseeID, + const char *AliaseeKeyword, unsigned AliaseeKWLen, + const LangOptions &LangOpts, IdentifierTable &Table) { + IdentifierInfo &AliasInfo = Table.get(Keyword, Keyword+KWLen); + IdentifierInfo &AliaseeInfo = Table.get(AliaseeKeyword, + AliaseeKeyword+AliaseeKWLen); + AliasInfo.setTokenID(AliaseeID); + AliasInfo.setIsExtensionToken(AliaseeInfo.isExtensionToken()); +} + +/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative +/// representations. +static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen, + tok::TokenKind TokenCode, + IdentifierTable &Table) { + IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen); + Info.setTokenID(TokenCode); + Info.setIsCPlusPlusOperatorKeyword(); +} + +/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or +/// "property". +static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID, + const char *Name, unsigned NameLen, + IdentifierTable &Table) { + Table.get(Name, Name+NameLen).setObjCKeywordID(ObjCID); +} + +/// AddKeywords - Add all keywords to the symbol table. +/// +void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { + enum { + C90Shift = 0, + EXTC90 = 1 << C90Shift, + NOTC90 = 2 << C90Shift, + C99Shift = 2, + EXTC99 = 1 << C99Shift, + NOTC99 = 2 << C99Shift, + CPPShift = 4, + EXTCPP = 1 << CPPShift, + NOTCPP = 2 << CPPShift, + CPP0xShift = 6, + EXTCPP0x = 1 << CPP0xShift, + NOTCPP0x = 2 << CPP0xShift, + BoolShift = 8, + BOOLSUPPORT = 1 << BoolShift, + Mask = 3 + }; + + // Add keywords and tokens for the current language. +#define KEYWORD(NAME, FLAGS) \ + AddKeyword(#NAME, strlen(#NAME), tok::kw_ ## NAME, \ + ((FLAGS) >> C90Shift) & Mask, \ + ((FLAGS) >> C99Shift) & Mask, \ + ((FLAGS) >> CPPShift) & Mask, \ + ((FLAGS) >> CPP0xShift) & Mask, \ + ((FLAGS) >> BoolShift) & Mask, LangOpts, *this); +#define ALIAS(NAME, TOK) \ + AddAlias(NAME, strlen(NAME), tok::kw_ ## TOK, #TOK, strlen(#TOK), \ + LangOpts, *this); +#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \ + if (LangOpts.CXXOperatorNames) \ + AddCXXOperatorKeyword(#NAME, strlen(#NAME), tok::ALIAS, *this); +#define OBJC1_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC1) \ + AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this); +#define OBJC2_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC2) \ + AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this); +#include "clang/Basic/TokenKinds.def" +} + +tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { + // We use a perfect hash function here involving the length of the keyword, + // the first and third character. For preprocessor ID's there are no + // collisions (if there were, the switch below would complain about duplicate + // case values). Note that this depends on 'if' being null terminated. + +#define HASH(LEN, FIRST, THIRD) \ + (LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31) +#define CASE(LEN, FIRST, THIRD, NAME) \ + case HASH(LEN, FIRST, THIRD): \ + return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME + + unsigned Len = getLength(); + if (Len < 2) return tok::pp_not_keyword; + const char *Name = getName(); + switch (HASH(Len, Name[0], Name[2])) { + default: return tok::pp_not_keyword; + CASE( 2, 'i', '\0', if); + CASE( 4, 'e', 'i', elif); + CASE( 4, 'e', 's', else); + CASE( 4, 'l', 'n', line); + CASE( 4, 's', 'c', sccs); + CASE( 5, 'e', 'd', endif); + CASE( 5, 'e', 'r', error); + CASE( 5, 'i', 'e', ident); + CASE( 5, 'i', 'd', ifdef); + CASE( 5, 'u', 'd', undef); + + CASE( 6, 'a', 's', assert); + CASE( 6, 'd', 'f', define); + CASE( 6, 'i', 'n', ifndef); + CASE( 6, 'i', 'p', import); + CASE( 6, 'p', 'a', pragma); + + CASE( 7, 'd', 'f', defined); + CASE( 7, 'i', 'c', include); + CASE( 7, 'w', 'r', warning); + + CASE( 8, 'u', 'a', unassert); + CASE(12, 'i', 'c', include_next); +#undef CASE +#undef HASH + } +} + +//===----------------------------------------------------------------------===// +// Stats Implementation +//===----------------------------------------------------------------------===// + +/// PrintStats - Print statistics about how well the identifier table is doing +/// at hashing identifiers. +void IdentifierTable::PrintStats() const { + unsigned NumBuckets = HashTable.getNumBuckets(); + unsigned NumIdentifiers = HashTable.getNumItems(); + unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers; + unsigned AverageIdentifierSize = 0; + unsigned MaxIdentifierLength = 0; + + // TODO: Figure out maximum times an identifier had to probe for -stats. + for (llvm::StringMap<IdentifierInfo, llvm::BumpPtrAllocator>::const_iterator + I = HashTable.begin(), E = HashTable.end(); I != E; ++I) { + unsigned IdLen = I->getKeyLength(); + AverageIdentifierSize += IdLen; + if (MaxIdentifierLength < IdLen) + MaxIdentifierLength = IdLen; + } + + fprintf(stderr, "\n*** Identifier Table Stats:\n"); + fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers); + fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets); + fprintf(stderr, "Hash density (#identifiers per bucket): %f\n", + NumIdentifiers/(double)NumBuckets); + fprintf(stderr, "Ave identifier length: %f\n", + (AverageIdentifierSize/(double)NumIdentifiers)); + fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength); + + // Compute statistics about the memory allocated for identifiers. + HashTable.getAllocator().PrintStats(); +} + +//===----------------------------------------------------------------------===// +// SelectorTable Implementation +//===----------------------------------------------------------------------===// + +unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) { + return DenseMapInfo<void*>::getHashValue(S.getAsOpaquePtr()); +} + + +/// MultiKeywordSelector - One of these variable length records is kept for each +/// selector containing more than one keyword. We use a folding set +/// to unique aggregate names (keyword selectors in ObjC parlance). Access to +/// this class is provided strictly through Selector. +namespace clang { +class MultiKeywordSelector : public llvm::FoldingSetNode { + friend SelectorTable* SelectorTable::CreateAndRegister(llvm::Deserializer&); + MultiKeywordSelector(unsigned nKeys) : NumArgs(nKeys) {} +public: + unsigned NumArgs; + + // Constructor for keyword selectors. + MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) { + assert((nKeys > 1) && "not a multi-keyword selector"); + NumArgs = nKeys; + + // Fill in the trailing keyword array. + IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this+1); + for (unsigned i = 0; i != nKeys; ++i) + KeyInfo[i] = IIV[i]; + } + + // getName - Derive the full selector name and return it. + std::string getName() const; + + unsigned getNumArgs() const { return NumArgs; } + + typedef IdentifierInfo *const *keyword_iterator; + keyword_iterator keyword_begin() const { + return reinterpret_cast<keyword_iterator>(this+1); + } + keyword_iterator keyword_end() const { + return keyword_begin()+NumArgs; + } + IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { + assert(i < NumArgs && "getIdentifierInfoForSlot(): illegal index"); + return keyword_begin()[i]; + } + static void Profile(llvm::FoldingSetNodeID &ID, + keyword_iterator ArgTys, unsigned NumArgs) { + ID.AddInteger(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + ID.AddPointer(ArgTys[i]); + } + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, keyword_begin(), NumArgs); + } +}; +} // end namespace clang. + +unsigned Selector::getNumArgs() const { + unsigned IIF = getIdentifierInfoFlag(); + if (IIF == ZeroArg) + return 0; + if (IIF == OneArg) + return 1; + // We point to a MultiKeywordSelector (pointer doesn't contain any flags). + MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr); + return SI->getNumArgs(); +} + +IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { + if (IdentifierInfo *II = getAsIdentifierInfo()) { + assert(argIndex == 0 && "illegal keyword index"); + return II; + } + // We point to a MultiKeywordSelector (pointer doesn't contain any flags). + MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr); + return SI->getIdentifierInfoForSlot(argIndex); +} + +std::string MultiKeywordSelector::getName() const { + std::string Result; + unsigned Length = 0; + for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { + if (*I) + Length += (*I)->getLength(); + ++Length; // : + } + + Result.reserve(Length); + + for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { + if (*I) + Result.insert(Result.end(), (*I)->getName(), + (*I)->getName()+(*I)->getLength()); + Result.push_back(':'); + } + + return Result; +} + +std::string Selector::getName() const { + if (IdentifierInfo *II = getAsIdentifierInfo()) { + if (getNumArgs() == 0) + return II->getName(); + + std::string Res = II->getName(); + Res += ":"; + return Res; + } + + // We have a multiple keyword selector (no embedded flags). + return reinterpret_cast<MultiKeywordSelector *>(InfoPtr)->getName(); +} + + +Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { + if (nKeys < 2) + return Selector(IIV[0], nKeys); + + llvm::FoldingSet<MultiKeywordSelector> *SelTab; + + SelTab = static_cast<llvm::FoldingSet<MultiKeywordSelector> *>(Impl); + + // Unique selector, to guarantee there is one per name. + llvm::FoldingSetNodeID ID; + MultiKeywordSelector::Profile(ID, IIV, nKeys); + + void *InsertPos = 0; + if (MultiKeywordSelector *SI = SelTab->FindNodeOrInsertPos(ID, InsertPos)) + return Selector(SI); + + // MultiKeywordSelector objects are not allocated with new because they have a + // variable size array (for parameter types) at the end of them. + MultiKeywordSelector *SI = + (MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) + + nKeys*sizeof(IdentifierInfo *)); + new (SI) MultiKeywordSelector(nKeys, IIV); + SelTab->InsertNode(SI, InsertPos); + return Selector(SI); +} + +SelectorTable::SelectorTable() { + Impl = new llvm::FoldingSet<MultiKeywordSelector>; +} + +SelectorTable::~SelectorTable() { + delete static_cast<llvm::FoldingSet<MultiKeywordSelector> *>(Impl); +} + +//===----------------------------------------------------------------------===// +// Serialization for IdentifierInfo and IdentifierTable. +//===----------------------------------------------------------------------===// + +void IdentifierInfo::Emit(llvm::Serializer& S) const { + S.EmitInt(getTokenID()); + S.EmitInt(getBuiltinID()); + S.EmitInt(getObjCKeywordID()); + S.EmitBool(hasMacroDefinition()); + S.EmitBool(isExtensionToken()); + S.EmitBool(isPoisoned()); + S.EmitBool(isCPlusPlusOperatorKeyword()); + // FIXME: FETokenInfo +} + +void IdentifierInfo::Read(llvm::Deserializer& D) { + setTokenID((tok::TokenKind) D.ReadInt()); + setBuiltinID(D.ReadInt()); + setObjCKeywordID((tok::ObjCKeywordKind) D.ReadInt()); + setHasMacroDefinition(D.ReadBool()); + setIsExtensionToken(D.ReadBool()); + setIsPoisoned(D.ReadBool()); + setIsCPlusPlusOperatorKeyword(D.ReadBool()); + // FIXME: FETokenInfo +} + +void IdentifierTable::Emit(llvm::Serializer& S) const { + S.EnterBlock(); + + S.EmitPtr(this); + + for (iterator I=begin(), E=end(); I != E; ++I) { + const char* Key = I->getKeyData(); + const IdentifierInfo* Info = &I->getValue(); + + bool KeyRegistered = S.isRegistered(Key); + bool InfoRegistered = S.isRegistered(Info); + + if (KeyRegistered || InfoRegistered) { + // These acrobatics are so that we don't incur the cost of registering + // a pointer with the backpatcher during deserialization if nobody + // references the object. + S.EmitPtr(InfoRegistered ? Info : NULL); + S.EmitPtr(KeyRegistered ? Key : NULL); + S.EmitCStr(Key); + S.Emit(*Info); + } + } + + S.ExitBlock(); +} + +IdentifierTable* IdentifierTable::CreateAndRegister(llvm::Deserializer& D) { + llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); + + std::vector<char> buff; + buff.reserve(200); + + IdentifierTable* t = new IdentifierTable(); + D.RegisterPtr(t); + + while (!D.FinishedBlock(BLoc)) { + llvm::SerializedPtrID InfoPtrID = D.ReadPtrID(); + llvm::SerializedPtrID KeyPtrID = D.ReadPtrID(); + + D.ReadCStr(buff); + + llvm::StringMapEntry<IdentifierInfo>& Entry = + t->HashTable.GetOrCreateValue(&buff[0],&buff[0]+buff.size()); + + D.Read(Entry.getValue()); + + if (InfoPtrID) + D.RegisterRef(InfoPtrID,Entry.getValue()); + + if (KeyPtrID) + D.RegisterPtr(KeyPtrID,Entry.getKeyData()); + } + + return t; +} + +//===----------------------------------------------------------------------===// +// Serialization for Selector and SelectorTable. +//===----------------------------------------------------------------------===// + +void Selector::Emit(llvm::Serializer& S) const { + S.EmitInt(getIdentifierInfoFlag()); + S.EmitPtr(reinterpret_cast<void*>(InfoPtr & ~ArgFlags)); +} + +Selector Selector::ReadVal(llvm::Deserializer& D) { + unsigned flag = D.ReadInt(); + + uintptr_t ptr; + D.ReadUIntPtr(ptr,false); // No backpatching. + + return Selector(ptr | flag); +} + +void SelectorTable::Emit(llvm::Serializer& S) const { + typedef llvm::FoldingSet<MultiKeywordSelector>::iterator iterator; + llvm::FoldingSet<MultiKeywordSelector> *SelTab; + SelTab = static_cast<llvm::FoldingSet<MultiKeywordSelector> *>(Impl); + + S.EnterBlock(); + + S.EmitPtr(this); + + for (iterator I=SelTab->begin(), E=SelTab->end(); I != E; ++I) { + if (!S.isRegistered(&*I)) + continue; + + S.FlushRecord(); // Start a new record. + + S.EmitPtr(&*I); + S.EmitInt(I->getNumArgs()); + + for (MultiKeywordSelector::keyword_iterator KI = I->keyword_begin(), + KE = I->keyword_end(); KI != KE; ++KI) + S.EmitPtr(*KI); + } + + S.ExitBlock(); +} + +SelectorTable* SelectorTable::CreateAndRegister(llvm::Deserializer& D) { + llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); + + SelectorTable* t = new SelectorTable(); + D.RegisterPtr(t); + + llvm::FoldingSet<MultiKeywordSelector>& SelTab = + *static_cast<llvm::FoldingSet<MultiKeywordSelector>*>(t->Impl); + + while (!D.FinishedBlock(BLoc)) { + + llvm::SerializedPtrID PtrID = D.ReadPtrID(); + unsigned nKeys = D.ReadInt(); + + MultiKeywordSelector *SI = + (MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) + + nKeys*sizeof(IdentifierInfo *)); + + new (SI) MultiKeywordSelector(nKeys); + + D.RegisterPtr(PtrID,SI); + + IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(SI+1); + + for (unsigned i = 0; i != nKeys; ++i) + D.ReadPtr(KeyInfo[i],false); + + SelTab.GetOrInsertNode(SI); + } + + return t; +} diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp new file mode 100644 index 00000000000..f7fd91fbda5 --- /dev/null +++ b/clang/lib/Basic/LangOptions.cpp @@ -0,0 +1,58 @@ +//===--- LangOptions.cpp - Language feature info --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the methods for LangOptions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/LangOptions.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; + +void LangOptions::Emit(llvm::Serializer& S) const { + S.EmitBool((bool) Trigraphs); + S.EmitBool((bool) BCPLComment); + S.EmitBool((bool) DollarIdents); + S.EmitBool((bool) Digraphs); + S.EmitBool((bool) HexFloats); + S.EmitBool((bool) C99); + S.EmitBool((bool) Microsoft); + S.EmitBool((bool) CPlusPlus); + S.EmitBool((bool) CPlusPlus0x); + S.EmitBool((bool) NoExtensions); + S.EmitBool((bool) CXXOperatorNames); + S.EmitBool((bool) ObjC1); + S.EmitBool((bool) ObjC2); + S.EmitBool((bool) PascalStrings); + S.EmitBool((bool) Boolean); + S.EmitBool((bool) WritableStrings); + S.EmitBool((bool) LaxVectorConversions); +} + +void LangOptions::Read(llvm::Deserializer& D) { + Trigraphs = D.ReadBool() ? 1 : 0; + BCPLComment = D.ReadBool() ? 1 : 0; + DollarIdents = D.ReadBool() ? 1 : 0; + Digraphs = D.ReadBool() ? 1 : 0; + HexFloats = D.ReadBool() ? 1 : 0; + C99 = D.ReadBool() ? 1 : 0; + Microsoft = D.ReadBool() ? 1 : 0; + CPlusPlus = D.ReadBool() ? 1 : 0; + CPlusPlus0x = D.ReadBool() ? 1 : 0; + NoExtensions = D.ReadBool() ? 1 : 0; + CXXOperatorNames = D.ReadBool() ? 1 : 0; + ObjC1 = D.ReadBool() ? 1 : 0; + ObjC2 = D.ReadBool() ? 1 : 0; + PascalStrings = D.ReadBool() ? 1 : 0; + Boolean = D.ReadBool() ? 1 : 0; + WritableStrings = D.ReadBool() ? 1 : 0; + LaxVectorConversions = D.ReadBool() ? 1 : 0; +} diff --git a/clang/lib/Basic/Makefile b/clang/lib/Basic/Makefile new file mode 100644 index 00000000000..e95d6dbfa35 --- /dev/null +++ b/clang/lib/Basic/Makefile @@ -0,0 +1,22 @@ +##===- clang/lib/Basic/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the Basic library for the C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangBasic +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/clang/lib/Basic/SourceLocation.cpp b/clang/lib/Basic/SourceLocation.cpp new file mode 100644 index 00000000000..eaf129f251e --- /dev/null +++ b/clang/lib/Basic/SourceLocation.cpp @@ -0,0 +1,79 @@ +//==--- SourceLocation.cpp - Compact identifier for Source Files -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines serialization methods for the SourceLocation class. +// This file defines accessor methods for the FullSourceLoc class. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; + +void SourceLocation::Emit(llvm::Serializer& S) const { + S.EmitInt(getRawEncoding()); +} + +SourceLocation SourceLocation::ReadVal(llvm::Deserializer& D) { + return SourceLocation::getFromRawEncoding(D.ReadInt()); +} + +void SourceRange::Emit(llvm::Serializer& S) const { + B.Emit(S); + E.Emit(S); +} + +SourceRange SourceRange::ReadVal(llvm::Deserializer& D) { + SourceLocation A = SourceLocation::ReadVal(D); + SourceLocation B = SourceLocation::ReadVal(D); + return SourceRange(A,B); +} + +FullSourceLoc FullSourceLoc::getLogicalLoc() { + assert (isValid()); + return FullSourceLoc(SrcMgr->getLogicalLoc(Loc),*SrcMgr); +} + +FullSourceLoc FullSourceLoc::getIncludeLoc() { + assert (isValid()); + return FullSourceLoc(SrcMgr->getIncludeLoc(Loc),*SrcMgr); +} + +unsigned FullSourceLoc::getLineNumber() { + assert (isValid()); + return SrcMgr->getLineNumber(Loc); +} + +unsigned FullSourceLoc::getColumnNumber() { + assert (isValid()); + return SrcMgr->getColumnNumber(Loc); +} + +const char* FullSourceLoc::getSourceName() const { + assert (isValid()); + return SrcMgr->getSourceName(Loc); +} + +const FileEntry* FullSourceLoc::getFileEntryForLoc() const { + assert (isValid()); + return SrcMgr->getFileEntryForLoc(Loc); +} + +const char * FullSourceLoc::getCharacterData() const { + assert (isValid()); + return SrcMgr->getCharacterData(Loc); +} + +const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const { + assert (isValid()); + return SrcMgr->getBuffer(Loc.getFileID()); +} diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp new file mode 100644 index 00000000000..73ac2abe26f --- /dev/null +++ b/clang/lib/Basic/SourceManager.cpp @@ -0,0 +1,574 @@ +//===--- SourceManager.cpp - Track and cache source files -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SourceManager interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "llvm/Config/config.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Path.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" +#include "llvm/Support/Streams.h" +#include <algorithm> +#include <fcntl.h> +using namespace clang; +using namespace SrcMgr; +using llvm::MemoryBuffer; + +ContentCache::~ContentCache() { + delete Buffer; + delete [] SourceLineCache; +} + +// FIXME: REMOVE THESE +#include <unistd.h> +#include <sys/types.h> +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <sys/uio.h> +#include <sys/fcntl.h> +#else +#include <io.h> +#endif +#include <cerrno> + +static const MemoryBuffer *ReadFileFast(const FileEntry *FileEnt) { +#if 0 + // FIXME: Reintroduce this and zap this function once the common llvm stuff + // is fast for the small case. + return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()), + FileEnt->getSize()); +#endif + + // If the file is larger than some threshold, use 'read', otherwise use mmap. + if (FileEnt->getSize() >= 4096*4) + return MemoryBuffer::getFile(FileEnt->getName(), strlen(FileEnt->getName()), + 0, FileEnt->getSize()); + + MemoryBuffer *SB = MemoryBuffer::getNewUninitMemBuffer(FileEnt->getSize(), + FileEnt->getName()); + char *BufPtr = const_cast<char*>(SB->getBufferStart()); + +#if defined(LLVM_ON_WIN32) + int FD = ::open(FileEnt->getName(), O_RDONLY|O_BINARY); +#else + int FD = ::open(FileEnt->getName(), O_RDONLY); +#endif + if (FD == -1) { + delete SB; + return 0; + } + + unsigned BytesLeft = FileEnt->getSize(); + while (BytesLeft) { + ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); + if (NumRead != -1) { + BytesLeft -= NumRead; + BufPtr += NumRead; + } else if (errno == EINTR) { + // try again + } else { + // error reading. + close(FD); + delete SB; + return 0; + } + } + close(FD); + + return SB; +} + + +/// getFileInfo - Create or return a cached FileInfo for the specified file. +/// +const ContentCache* SourceManager::getContentCache(const FileEntry *FileEnt) { + + assert(FileEnt && "Didn't specify a file entry to use?"); + // Do we already have information about this file? + std::set<ContentCache>::iterator I = + FileInfos.lower_bound(ContentCache(FileEnt)); + + if (I != FileInfos.end() && I->Entry == FileEnt) + return &*I; + + // Nope, get information. + const MemoryBuffer *File = ReadFileFast(FileEnt); + if (File == 0) + return 0; + + ContentCache& Entry = const_cast<ContentCache&>(*FileInfos.insert(I,FileEnt)); + + Entry.Buffer = File; + Entry.SourceLineCache = 0; + Entry.NumLines = 0; + return &Entry; +} + + +/// createMemBufferContentCache - Create a new ContentCache for the specified +/// memory buffer. This does no caching. +const ContentCache* +SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) { + // Add a new ContentCache to the MemBufferInfos list and return it. We + // must default construct the object first that the instance actually + // stored within MemBufferInfos actually owns the Buffer, and not any + // temporary we would use in the call to "push_back". + MemBufferInfos.push_back(ContentCache()); + ContentCache& Entry = const_cast<ContentCache&>(MemBufferInfos.back()); + Entry.Buffer = Buffer; + return &Entry; +} + + +/// createFileID - Create a new fileID for the specified ContentCache and +/// include position. This works regardless of whether the ContentCache +/// corresponds to a file or some other input source. +unsigned SourceManager::createFileID(const ContentCache *File, + SourceLocation IncludePos) { + // If FileEnt is really large (e.g. it's a large .i file), we may not be able + // to fit an arbitrary position in the file in the FilePos field. To handle + // this, we create one FileID for each chunk of the file that fits in a + // FilePos field. + unsigned FileSize = File->Buffer->getBufferSize(); + if (FileSize+1 < (1 << SourceLocation::FilePosBits)) { + FileIDs.push_back(FileIDInfo::get(IncludePos, 0, File)); + assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) && + "Ran out of file ID's!"); + return FileIDs.size(); + } + + // Create one FileID for each chunk of the file. + unsigned Result = FileIDs.size()+1; + + unsigned ChunkNo = 0; + while (1) { + FileIDs.push_back(FileIDInfo::get(IncludePos, ChunkNo++, File)); + + if (FileSize+1 < (1 << SourceLocation::FilePosBits)) break; + FileSize -= (1 << SourceLocation::FilePosBits); + } + + assert(FileIDs.size() < (1 << SourceLocation::FileIDBits) && + "Ran out of file ID's!"); + return Result; +} + +/// getInstantiationLoc - Return a new SourceLocation that encodes the fact +/// that a token from physloc PhysLoc should actually be referenced from +/// InstantiationLoc. +SourceLocation SourceManager::getInstantiationLoc(SourceLocation PhysLoc, + SourceLocation InstantLoc) { + // The specified source location may be a mapped location, due to a macro + // instantiation or #line directive. Strip off this information to find out + // where the characters are actually located. + PhysLoc = getPhysicalLoc(PhysLoc); + + // Resolve InstantLoc down to a real logical location. + InstantLoc = getLogicalLoc(InstantLoc); + + + // If the last macro id is close to the currently requested location, try to + // reuse it. This implements a small cache. + for (int i = MacroIDs.size()-1, e = MacroIDs.size()-6; i >= 0 && i != e; --i){ + MacroIDInfo &LastOne = MacroIDs[i]; + + // The instanitation point and source physloc have to exactly match to reuse + // (for now). We could allow "nearby" instantiations in the future. + if (LastOne.getVirtualLoc() != InstantLoc || + LastOne.getPhysicalLoc().getFileID() != PhysLoc.getFileID()) + continue; + + // Check to see if the physloc of the token came from near enough to reuse. + int PhysDelta = PhysLoc.getRawFilePos() - + LastOne.getPhysicalLoc().getRawFilePos(); + if (SourceLocation::isValidMacroPhysOffs(PhysDelta)) + return SourceLocation::getMacroLoc(i, PhysDelta); + } + + + MacroIDs.push_back(MacroIDInfo::get(InstantLoc, PhysLoc)); + return SourceLocation::getMacroLoc(MacroIDs.size()-1, 0); +} + +/// getBufferData - Return a pointer to the start and end of the character +/// data for the specified FileID. +std::pair<const char*, const char*> +SourceManager::getBufferData(unsigned FileID) const { + const llvm::MemoryBuffer *Buf = getBuffer(FileID); + return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd()); +} + + +/// getCharacterData - Return a pointer to the start of the specified location +/// in the appropriate MemoryBuffer. +const char *SourceManager::getCharacterData(SourceLocation SL) const { + // Note that this is a hot function in the getSpelling() path, which is + // heavily used by -E mode. + SL = getPhysicalLoc(SL); + + return getContentCache(SL.getFileID())->Buffer->getBufferStart() + + getFullFilePos(SL); +} + + +/// getColumnNumber - Return the column # for the specified file position. +/// this is significantly cheaper to compute than the line number. This returns +/// zero if the column number isn't known. +unsigned SourceManager::getColumnNumber(SourceLocation Loc) const { + unsigned FileID = Loc.getFileID(); + if (FileID == 0) return 0; + + unsigned FilePos = getFullFilePos(Loc); + const MemoryBuffer *Buffer = getBuffer(FileID); + const char *Buf = Buffer->getBufferStart(); + + unsigned LineStart = FilePos; + while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r') + --LineStart; + return FilePos-LineStart+1; +} + +/// getSourceName - This method returns the name of the file or buffer that +/// the SourceLocation specifies. This can be modified with #line directives, +/// etc. +const char *SourceManager::getSourceName(SourceLocation Loc) const { + unsigned FileID = Loc.getFileID(); + if (FileID == 0) return ""; + return getContentCache(FileID)->Buffer->getBufferIdentifier(); +} + +static void ComputeLineNumbers(ContentCache* FI) DISABLE_INLINE; +static void ComputeLineNumbers(ContentCache* FI) { + const MemoryBuffer *Buffer = FI->Buffer; + + // Find the file offsets of all of the *physical* source lines. This does + // not look at trigraphs, escaped newlines, or anything else tricky. + std::vector<unsigned> LineOffsets; + + // Line #1 starts at char 0. + LineOffsets.push_back(0); + + const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart(); + const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd(); + unsigned Offs = 0; + while (1) { + // Skip over the contents of the line. + // TODO: Vectorize this? This is very performance sensitive for programs + // with lots of diagnostics and in -E mode. + const unsigned char *NextBuf = (const unsigned char *)Buf; + while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0') + ++NextBuf; + Offs += NextBuf-Buf; + Buf = NextBuf; + + if (Buf[0] == '\n' || Buf[0] == '\r') { + // If this is \n\r or \r\n, skip both characters. + if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1]) + ++Offs, ++Buf; + ++Offs, ++Buf; + LineOffsets.push_back(Offs); + } else { + // Otherwise, this is a null. If end of file, exit. + if (Buf == End) break; + // Otherwise, skip the null. + ++Offs, ++Buf; + } + } + + // Copy the offsets into the FileInfo structure. + FI->NumLines = LineOffsets.size(); + FI->SourceLineCache = new unsigned[LineOffsets.size()]; + std::copy(LineOffsets.begin(), LineOffsets.end(), FI->SourceLineCache); +} + +/// getLineNumber - Given a SourceLocation, return the physical line number +/// for the position indicated. This requires building and caching a table of +/// line offsets for the MemoryBuffer, so this is not cheap: use only when +/// about to emit a diagnostic. +unsigned SourceManager::getLineNumber(SourceLocation Loc) { + unsigned FileID = Loc.getFileID(); + if (FileID == 0) return 0; + + ContentCache* Content; + + if (LastLineNoFileIDQuery == FileID) + Content = LastLineNoContentCache; + else + Content = const_cast<ContentCache*>(getContentCache(FileID)); + + // If this is the first use of line information for this buffer, compute the + /// SourceLineCache for it on demand. + if (Content->SourceLineCache == 0) + ComputeLineNumbers(Content); + + // Okay, we know we have a line number table. Do a binary search to find the + // line number that this character position lands on. + unsigned *SourceLineCache = Content->SourceLineCache; + unsigned *SourceLineCacheStart = SourceLineCache; + unsigned *SourceLineCacheEnd = SourceLineCache + Content->NumLines; + + unsigned QueriedFilePos = getFullFilePos(Loc)+1; + + // If the previous query was to the same file, we know both the file pos from + // that query and the line number returned. This allows us to narrow the + // search space from the entire file to something near the match. + if (LastLineNoFileIDQuery == FileID) { + if (QueriedFilePos >= LastLineNoFilePos) { + SourceLineCache = SourceLineCache+LastLineNoResult-1; + + // The query is likely to be nearby the previous one. Here we check to + // see if it is within 5, 10 or 20 lines. It can be far away in cases + // where big comment blocks and vertical whitespace eat up lines but + // contribute no tokens. + if (SourceLineCache+5 < SourceLineCacheEnd) { + if (SourceLineCache[5] > QueriedFilePos) + SourceLineCacheEnd = SourceLineCache+5; + else if (SourceLineCache+10 < SourceLineCacheEnd) { + if (SourceLineCache[10] > QueriedFilePos) + SourceLineCacheEnd = SourceLineCache+10; + else if (SourceLineCache+20 < SourceLineCacheEnd) { + if (SourceLineCache[20] > QueriedFilePos) + SourceLineCacheEnd = SourceLineCache+20; + } + } + } + } else { + SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1; + } + } + + // If the spread is large, do a "radix" test as our initial guess, based on + // the assumption that lines average to approximately the same length. + // NOTE: This is currently disabled, as it does not appear to be profitable in + // initial measurements. + if (0 && SourceLineCacheEnd-SourceLineCache > 20) { + unsigned FileLen = Content->SourceLineCache[Content->NumLines-1]; + + // Take a stab at guessing where it is. + unsigned ApproxPos = Content->NumLines*QueriedFilePos / FileLen; + + // Check for -10 and +10 lines. + unsigned LowerBound = std::max(int(ApproxPos-10), 0); + unsigned UpperBound = std::min(ApproxPos+10, FileLen); + + // If the computed lower bound is less than the query location, move it in. + if (SourceLineCache < SourceLineCacheStart+LowerBound && + SourceLineCacheStart[LowerBound] < QueriedFilePos) + SourceLineCache = SourceLineCacheStart+LowerBound; + + // If the computed upper bound is greater than the query location, move it. + if (SourceLineCacheEnd > SourceLineCacheStart+UpperBound && + SourceLineCacheStart[UpperBound] >= QueriedFilePos) + SourceLineCacheEnd = SourceLineCacheStart+UpperBound; + } + + unsigned *Pos + = std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos); + unsigned LineNo = Pos-SourceLineCacheStart; + + LastLineNoFileIDQuery = FileID; + LastLineNoContentCache = Content; + LastLineNoFilePos = QueriedFilePos; + LastLineNoResult = LineNo; + return LineNo; +} + +/// PrintStats - Print statistics to stderr. +/// +void SourceManager::PrintStats() const { + llvm::cerr << "\n*** Source Manager Stats:\n"; + llvm::cerr << FileInfos.size() << " files mapped, " << MemBufferInfos.size() + << " mem buffers mapped, " << FileIDs.size() + << " file ID's allocated.\n"; + llvm::cerr << " " << FileIDs.size() << " normal buffer FileID's, " + << MacroIDs.size() << " macro expansion FileID's.\n"; + + unsigned NumLineNumsComputed = 0; + unsigned NumFileBytesMapped = 0; + for (std::set<ContentCache>::const_iterator I = + FileInfos.begin(), E = FileInfos.end(); I != E; ++I) { + NumLineNumsComputed += I->SourceLineCache != 0; + NumFileBytesMapped += I->Buffer->getBufferSize(); + } + + llvm::cerr << NumFileBytesMapped << " bytes of files mapped, " + << NumLineNumsComputed << " files with line #'s computed.\n"; +} + +//===----------------------------------------------------------------------===// +// Serialization. +//===----------------------------------------------------------------------===// + +void ContentCache::Emit(llvm::Serializer& S) const { + S.FlushRecord(); + S.EmitPtr(this); + + if (Entry) { + llvm::sys::Path Fname(Buffer->getBufferIdentifier()); + + if (Fname.isAbsolute()) + S.EmitCStr(Fname.c_str()); + else { + // Create an absolute path. + // FIXME: This will potentially contain ".." and "." in the path. + llvm::sys::Path path = llvm::sys::Path::GetCurrentDirectory(); + path.appendComponent(Fname.c_str()); + S.EmitCStr(path.c_str()); + } + } + else { + const char* p = Buffer->getBufferStart(); + const char* e = Buffer->getBufferEnd(); + + S.EmitInt(e-p); + + for ( ; p != e; ++p) + S.EmitInt(*p); + } + + S.FlushRecord(); +} + +void ContentCache::ReadToSourceManager(llvm::Deserializer& D, + SourceManager& SMgr, + FileManager* FMgr, + std::vector<char>& Buf) { + if (FMgr) { + llvm::SerializedPtrID PtrID = D.ReadPtrID(); + D.ReadCStr(Buf,false); + + // Create/fetch the FileEntry. + const char* start = &Buf[0]; + const FileEntry* E = FMgr->getFile(start,start+Buf.size()); + + // FIXME: Ideally we want a lazy materialization of the ContentCache + // anyway, because we don't want to read in source files unless this + // is absolutely needed. + if (!E) + D.RegisterPtr(PtrID,NULL); + else + // Get the ContextCache object and register it with the deserializer. + D.RegisterPtr(PtrID,SMgr.getContentCache(E)); + } + else { + // Register the ContextCache object with the deserializer. + SMgr.MemBufferInfos.push_back(ContentCache()); + ContentCache& Entry = const_cast<ContentCache&>(SMgr.MemBufferInfos.back()); + D.RegisterPtr(&Entry); + + // Create the buffer. + unsigned Size = D.ReadInt(); + Entry.Buffer = MemoryBuffer::getNewUninitMemBuffer(Size); + + // Read the contents of the buffer. + char* p = const_cast<char*>(Entry.Buffer->getBufferStart()); + for (unsigned i = 0; i < Size ; ++i) + p[i] = D.ReadInt(); + } +} + +void FileIDInfo::Emit(llvm::Serializer& S) const { + S.Emit(IncludeLoc); + S.EmitInt(ChunkNo); + S.EmitPtr(Content); +} + +FileIDInfo FileIDInfo::ReadVal(llvm::Deserializer& D) { + FileIDInfo I; + I.IncludeLoc = SourceLocation::ReadVal(D); + I.ChunkNo = D.ReadInt(); + D.ReadPtr(I.Content,false); + return I; +} + +void MacroIDInfo::Emit(llvm::Serializer& S) const { + S.Emit(VirtualLoc); + S.Emit(PhysicalLoc); +} + +MacroIDInfo MacroIDInfo::ReadVal(llvm::Deserializer& D) { + MacroIDInfo I; + I.VirtualLoc = SourceLocation::ReadVal(D); + I.PhysicalLoc = SourceLocation::ReadVal(D); + return I; +} + +void SourceManager::Emit(llvm::Serializer& S) const { + S.EnterBlock(); + S.EmitPtr(this); + S.EmitInt(MainFileID); + + // Emit: FileInfos. Just emit the file name. + S.EnterBlock(); + + std::for_each(FileInfos.begin(),FileInfos.end(), + S.MakeEmitter<ContentCache>()); + + S.ExitBlock(); + + // Emit: MemBufferInfos + S.EnterBlock(); + + std::for_each(MemBufferInfos.begin(), MemBufferInfos.end(), + S.MakeEmitter<ContentCache>()); + + S.ExitBlock(); + + // Emit: FileIDs + S.EmitInt(FileIDs.size()); + std::for_each(FileIDs.begin(), FileIDs.end(), S.MakeEmitter<FileIDInfo>()); + + // Emit: MacroIDs + S.EmitInt(MacroIDs.size()); + std::for_each(MacroIDs.begin(), MacroIDs.end(), S.MakeEmitter<MacroIDInfo>()); + + S.ExitBlock(); +} + +SourceManager* +SourceManager::CreateAndRegister(llvm::Deserializer& D, FileManager& FMgr){ + SourceManager *M = new SourceManager(); + D.RegisterPtr(M); + + // Read: the FileID of the main source file of the translation unit. + M->MainFileID = D.ReadInt(); + + std::vector<char> Buf; + + { // Read: FileInfos. + llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); + while (!D.FinishedBlock(BLoc)) + ContentCache::ReadToSourceManager(D,*M,&FMgr,Buf); + } + + { // Read: MemBufferInfos. + llvm::Deserializer::Location BLoc = D.getCurrentBlockLocation(); + while (!D.FinishedBlock(BLoc)) + ContentCache::ReadToSourceManager(D,*M,NULL,Buf); + } + + // Read: FileIDs. + unsigned Size = D.ReadInt(); + M->FileIDs.reserve(Size); + for (; Size > 0 ; --Size) + M->FileIDs.push_back(FileIDInfo::ReadVal(D)); + + // Read: MacroIDs. + Size = D.ReadInt(); + M->MacroIDs.reserve(Size); + for (; Size > 0 ; --Size) + M->MacroIDs.push_back(MacroIDInfo::ReadVal(D)); + + return M; +} diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp new file mode 100644 index 00000000000..0a561d75cb8 --- /dev/null +++ b/clang/lib/Basic/TargetInfo.cpp @@ -0,0 +1,210 @@ +//===--- TargetInfo.cpp - Information about Target machine ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the TargetInfo and TargetInfoImpl interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/AST/Builtins.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +using namespace clang; + +// TargetInfo Constructor. +TargetInfo::TargetInfo(const std::string &T) : Triple(T) { + // Set defaults. These should be overridden by concrete targets as needed. + CharIsSigned = true; + WCharWidth = WCharAlign = 32; + FloatFormat = &llvm::APFloat::IEEEsingle; + DoubleFormat = &llvm::APFloat::IEEEdouble; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; +} + +// Out of line virtual dtor for TargetInfo. +TargetInfo::~TargetInfo() {} + +//===----------------------------------------------------------------------===// + + +static void removeGCCRegisterPrefix(const char *&Name) { + if (Name[0] == '%' || Name[0] == '#') + Name++; +} + +/// isValidGCCRegisterName - Returns whether the passed in string +/// is a valid register name according to GCC. This is used by Sema for +/// inline asm statements. +bool TargetInfo::isValidGCCRegisterName(const char *Name) const { + const char * const *Names; + unsigned NumNames; + + // Get rid of any register prefix. + removeGCCRegisterPrefix(Name); + + + if (strcmp(Name, "memory") == 0 || + strcmp(Name, "cc") == 0) + return true; + + getGCCRegNames(Names, NumNames); + + // If we have a number it maps to an entry in the register name array. + if (isdigit(Name[0])) { + char *End; + int n = (int)strtol(Name, &End, 0); + if (*End == 0) + return n >= 0 && (unsigned)n < NumNames; + } + + // Check register names. + for (unsigned i = 0; i < NumNames; i++) { + if (strcmp(Name, Names[i]) == 0) + return true; + } + + // Now check aliases. + const GCCRegAlias *Aliases; + unsigned NumAliases; + + getGCCRegAliases(Aliases, NumAliases); + for (unsigned i = 0; i < NumAliases; i++) { + for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { + if (!Aliases[i].Aliases[j]) + break; + if (strcmp(Aliases[i].Aliases[j], Name) == 0) + return true; + } + } + + return false; +} + +const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const { + assert(isValidGCCRegisterName(Name) && "Invalid register passed in"); + + removeGCCRegisterPrefix(Name); + + const char * const *Names; + unsigned NumNames; + + getGCCRegNames(Names, NumNames); + + // First, check if we have a number. + if (isdigit(Name[0])) { + char *End; + int n = (int)strtol(Name, &End, 0); + if (*End == 0) { + assert(n >= 0 && (unsigned)n < NumNames && + "Out of bounds register number!"); + return Names[n]; + } + } + + // Now check aliases. + const GCCRegAlias *Aliases; + unsigned NumAliases; + + getGCCRegAliases(Aliases, NumAliases); + for (unsigned i = 0; i < NumAliases; i++) { + for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { + if (!Aliases[i].Aliases[j]) + break; + if (strcmp(Aliases[i].Aliases[j], Name) == 0) + return Aliases[i].Register; + } + } + + return Name; +} + +bool TargetInfo::validateOutputConstraint(const char *Name, + ConstraintInfo &info) const +{ + // An output constraint must start with '=' or '+' + if (*Name != '=' && *Name != '+') + return false; + + if (*Name == '+') + info = CI_ReadWrite; + else + info = CI_None; + + Name++; + while (*Name) { + switch (*Name) { + default: + if (!validateAsmConstraint(*Name, info)) { + // FIXME: This assert is in place temporarily + // so we can add more constraints as we hit it. + // Eventually, an unknown constraint should just be treated as 'g'. + assert(0 && "Unknown output constraint type!"); + } + case '&': // early clobber. + break; + case 'r': // general register. + info = (ConstraintInfo)(info|CI_AllowsRegister); + break; + case 'm': // memory operand. + info = (ConstraintInfo)(info|CI_AllowsMemory); + break; + case 'g': // general register, memory operand or immediate integer. + info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister); + break; + } + + Name++; + } + + return true; +} + +bool TargetInfo::validateInputConstraint(const char *Name, + unsigned NumOutputs, + ConstraintInfo &info) const { + while (*Name) { + switch (*Name) { + default: + // Check if we have a matching constraint + if (*Name >= '0' && *Name <= '9') { + unsigned i = *Name - '0'; + + // Check if matching constraint is out of bounds. + if (i >= NumOutputs) + return false; + } else if (!validateAsmConstraint(*Name, info)) { + // FIXME: This assert is in place temporarily + // so we can add more constraints as we hit it. + // Eventually, an unknown constraint should just be treated as 'g'. + assert(0 && "Unknown input constraint type!"); + } + case '%': // commutative + // FIXME: Fail if % is used with the last operand. + break; + case 'i': // immediate integer. + case 'I': + case 'n': // immediate integer with a known value. + break; + case 'r': // general register. + info = (ConstraintInfo)(info|CI_AllowsRegister); + break; + case 'm': // memory operand. + info = (ConstraintInfo)(info|CI_AllowsMemory); + break; + case 'g': // general register, memory operand or immediate integer. + info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister); + break; + } + + Name++; + } + + return true; +} diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp new file mode 100644 index 00000000000..e8238daeae3 --- /dev/null +++ b/clang/lib/Basic/Targets.cpp @@ -0,0 +1,757 @@ +//===--- Targets.cpp - Implement -arch option and targets -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements construction of a TargetInfo object from a +// target triple. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Builtins.h" +#include "clang/AST/TargetBuiltins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/STLExtras.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Common code shared among targets. +//===----------------------------------------------------------------------===// + +static void Define(std::vector<char> &Buf, const char *Macro, + const char *Val = "1") { + const char *Def = "#define "; + Buf.insert(Buf.end(), Def, Def+strlen(Def)); + Buf.insert(Buf.end(), Macro, Macro+strlen(Macro)); + Buf.push_back(' '); + Buf.insert(Buf.end(), Val, Val+strlen(Val)); + Buf.push_back('\n'); +} + + +namespace { +class DarwinTargetInfo : public TargetInfo { +public: + DarwinTargetInfo(const std::string& triple) : TargetInfo(triple) {} + + virtual void getTargetDefines(std::vector<char> &Defs) const { +// FIXME: we need a real target configuration system. For now, only define +// __APPLE__ if the host has it. +#ifdef __APPLE__ + Define(Defs, "__APPLE__"); + Define(Defs, "__MACH__"); +#endif + + if (1) {// -fobjc-gc controls this. + Define(Defs, "__weak", ""); + Define(Defs, "__strong", ""); + } else { + Define(Defs, "__weak", "__attribute__((objc_gc(weak)))"); + Define(Defs, "__strong", "__attribute__((objc_gc(strong)))"); + Define(Defs, "__OBJC_GC__"); + } + + // darwin_constant_cfstrings controls this. + Define(Defs, "__CONSTANT_CFSTRINGS__"); + + if (0) // darwin_pascal_strings + Define(Defs, "__PASCAL_STRINGS__"); + } + +}; + + +class SolarisTargetInfo : public TargetInfo { +public: + SolarisTargetInfo(const std::string& triple) : TargetInfo(triple) {} + + virtual void getTargetDefines(std::vector<char> &Defs) const { +// FIXME: we need a real target configuration system. For now, only define +// __SUN__ if the host has it. +#ifdef __SUN__ + Define(Defs, "__SUN__"); + Define(Defs, "__SOLARIS__"); +#endif + + if (1) {// -fobjc-gc controls this. + Define(Defs, "__weak", ""); + Define(Defs, "__strong", ""); + } else { + Define(Defs, "__weak", "__attribute__((objc_gc(weak)))"); + Define(Defs, "__strong", "__attribute__((objc_gc(strong)))"); + Define(Defs, "__OBJC_GC__"); + } + } + +}; +} // end anonymous namespace. + + +/// getPowerPCDefines - Return a set of the PowerPC-specific #defines that are +/// not tied to a specific subtarget. +static void getPowerPCDefines(std::vector<char> &Defs, bool is64Bit) { + // Target identification. + Define(Defs, "__ppc__"); + Define(Defs, "_ARCH_PPC"); + Define(Defs, "__POWERPC__"); + if (is64Bit) { + Define(Defs, "_ARCH_PPC64"); + Define(Defs, "_LP64"); + Define(Defs, "__LP64__"); + Define(Defs, "__ppc64__"); + } else { + Define(Defs, "__ppc__"); + } + + // Target properties. + Define(Defs, "_BIG_ENDIAN"); + Define(Defs, "__BIG_ENDIAN__"); + + if (is64Bit) { + Define(Defs, "__INTMAX_MAX__", "9223372036854775807L"); + Define(Defs, "__INTMAX_TYPE__", "long int"); + Define(Defs, "__LONG_MAX__", "9223372036854775807L"); + Define(Defs, "__PTRDIFF_TYPE__", "long int"); + Define(Defs, "__UINTMAX_TYPE__", "long unsigned int"); + } else { + Define(Defs, "__INTMAX_MAX__", "9223372036854775807LL"); + Define(Defs, "__INTMAX_TYPE__", "long long int"); + Define(Defs, "__LONG_MAX__", "2147483647L"); + Define(Defs, "__PTRDIFF_TYPE__", "int"); + Define(Defs, "__UINTMAX_TYPE__", "long long unsigned int"); + } + Define(Defs, "__INT_MAX__", "2147483647"); + Define(Defs, "__LONG_LONG_MAX__", "9223372036854775807LL"); + Define(Defs, "__CHAR_BIT__", "8"); + Define(Defs, "__SCHAR_MAX__", "127"); + Define(Defs, "__SHRT_MAX__", "32767"); + Define(Defs, "__SIZE_TYPE__", "long unsigned int"); + + // Subtarget options. + Define(Defs, "__USER_LABEL_PREFIX__", "_"); + Define(Defs, "__NATURAL_ALIGNMENT__"); + Define(Defs, "__REGISTER_PREFIX__", ""); + + Define(Defs, "__WCHAR_MAX__", "2147483647"); + Define(Defs, "__WCHAR_TYPE__", "int"); + Define(Defs, "__WINT_TYPE__", "int"); + + // Float macros. + Define(Defs, "__FLT_DENORM_MIN__", "1.40129846e-45F"); + Define(Defs, "__FLT_DIG__", "6"); + Define(Defs, "__FLT_EPSILON__", "1.19209290e-7F"); + Define(Defs, "__FLT_EVAL_METHOD__", "0"); + Define(Defs, "__FLT_HAS_INFINITY__"); + Define(Defs, "__FLT_HAS_QUIET_NAN__"); + Define(Defs, "__FLT_MANT_DIG__", "24"); + Define(Defs, "__FLT_MAX_10_EXP__", "38"); + Define(Defs, "__FLT_MAX_EXP__", "128"); + Define(Defs, "__FLT_MAX__", "3.40282347e+38F"); + Define(Defs, "__FLT_MIN_10_EXP__", "(-37)"); + Define(Defs, "__FLT_MIN_EXP__", "(-125)"); + Define(Defs, "__FLT_MIN__", "1.17549435e-38F"); + Define(Defs, "__FLT_RADIX__", "2"); + + // double macros. + Define(Defs, "__DBL_DENORM_MIN__", "4.9406564584124654e-324"); + Define(Defs, "__DBL_DIG__", "15"); + Define(Defs, "__DBL_EPSILON__", "2.2204460492503131e-16"); + Define(Defs, "__DBL_HAS_INFINITY__"); + Define(Defs, "__DBL_HAS_QUIET_NAN__"); + Define(Defs, "__DBL_MANT_DIG__", "53"); + Define(Defs, "__DBL_MAX_10_EXP__", "308"); + Define(Defs, "__DBL_MAX_EXP__", "1024"); + Define(Defs, "__DBL_MAX__", "1.7976931348623157e+308"); + Define(Defs, "__DBL_MIN_10_EXP__", "(-307)"); + Define(Defs, "__DBL_MIN_EXP__", "(-1021)"); + Define(Defs, "__DBL_MIN__", "2.2250738585072014e-308"); + Define(Defs, "__DECIMAL_DIG__", "33"); + + // 128-bit long double macros. + Define(Defs, "__LDBL_DENORM_MIN__", + "4.94065645841246544176568792868221e-324L"); + Define(Defs, "__LDBL_DIG__", "31"); + Define(Defs, "__LDBL_EPSILON__", + "4.94065645841246544176568792868221e-324L"); + Define(Defs, "__LDBL_HAS_INFINITY__"); + Define(Defs, "__LDBL_HAS_QUIET_NAN__"); + Define(Defs, "__LDBL_MANT_DIG__", "106"); + Define(Defs, "__LDBL_MAX_10_EXP__", "308"); + Define(Defs, "__LDBL_MAX_EXP__", "1024"); + Define(Defs, "__LDBL_MAX__", + "1.79769313486231580793728971405301e+308L"); + Define(Defs, "__LDBL_MIN_10_EXP__", "(-291)"); + Define(Defs, "__LDBL_MIN_EXP__", "(-968)"); + Define(Defs, "__LDBL_MIN__", + "2.00416836000897277799610805135016e-292L"); + Define(Defs, "__LONG_DOUBLE_128__"); +} + +/// getX86Defines - Return a set of the X86-specific #defines that are +/// not tied to a specific subtarget. +static void getX86Defines(std::vector<char> &Defs, bool is64Bit) { + // Target identification. + if (is64Bit) { + Define(Defs, "_LP64"); + Define(Defs, "__LP64__"); + Define(Defs, "__amd64__"); + Define(Defs, "__amd64"); + Define(Defs, "__x86_64"); + Define(Defs, "__x86_64__"); + } else { + Define(Defs, "__i386__"); + Define(Defs, "__i386"); + Define(Defs, "i386"); + } + + // Target properties. + Define(Defs, "__LITTLE_ENDIAN__"); + + if (is64Bit) { + Define(Defs, "__INTMAX_MAX__", "9223372036854775807L"); + Define(Defs, "__INTMAX_TYPE__", "long int"); + Define(Defs, "__LONG_MAX__", "9223372036854775807L"); + Define(Defs, "__PTRDIFF_TYPE__", "long int"); + Define(Defs, "__UINTMAX_TYPE__", "long unsigned int"); + Define(Defs, "__SIZE_TYPE__", "long unsigned int"); + } else { + Define(Defs, "__INTMAX_MAX__", "9223372036854775807LL"); + Define(Defs, "__INTMAX_TYPE__", "long long int"); + Define(Defs, "__LONG_MAX__", "2147483647L"); + Define(Defs, "__PTRDIFF_TYPE__", "int"); + Define(Defs, "__UINTMAX_TYPE__", "long long unsigned int"); + Define(Defs, "__SIZE_TYPE__", "unsigned int"); + } + Define(Defs, "__CHAR_BIT__", "8"); + Define(Defs, "__INT_MAX__", "2147483647"); + Define(Defs, "__LONG_LONG_MAX__", "9223372036854775807LL"); + Define(Defs, "__SCHAR_MAX__", "127"); + Define(Defs, "__SHRT_MAX__", "32767"); + + // Subtarget options. + Define(Defs, "__nocona"); + Define(Defs, "__nocona__"); + Define(Defs, "__tune_nocona__"); + Define(Defs, "__SSE2_MATH__"); + Define(Defs, "__SSE2__"); + Define(Defs, "__SSE_MATH__"); + Define(Defs, "__SSE__"); + Define(Defs, "__MMX__"); + Define(Defs, "__REGISTER_PREFIX__", ""); + + Define(Defs, "__WCHAR_MAX__", "2147483647"); + Define(Defs, "__WCHAR_TYPE__", "int"); + Define(Defs, "__WINT_TYPE__", "int"); + + // Float macros. + Define(Defs, "__FLT_DENORM_MIN__", "1.40129846e-45F"); + Define(Defs, "__FLT_DIG__", "6"); + Define(Defs, "__FLT_EPSILON__", "1.19209290e-7F"); + Define(Defs, "__FLT_EVAL_METHOD__", "0"); + Define(Defs, "__FLT_HAS_INFINITY__"); + Define(Defs, "__FLT_HAS_QUIET_NAN__"); + Define(Defs, "__FLT_MANT_DIG__", "24"); + Define(Defs, "__FLT_MAX_10_EXP__", "38"); + Define(Defs, "__FLT_MAX_EXP__", "128"); + Define(Defs, "__FLT_MAX__", "3.40282347e+38F"); + Define(Defs, "__FLT_MIN_10_EXP__", "(-37)"); + Define(Defs, "__FLT_MIN_EXP__", "(-125)"); + Define(Defs, "__FLT_MIN__", "1.17549435e-38F"); + Define(Defs, "__FLT_RADIX__", "2"); + + // Double macros. + Define(Defs, "__DBL_DENORM_MIN__", "4.9406564584124654e-324"); + Define(Defs, "__DBL_DIG__", "15"); + Define(Defs, "__DBL_EPSILON__", "2.2204460492503131e-16"); + Define(Defs, "__DBL_HAS_INFINITY__"); + Define(Defs, "__DBL_HAS_QUIET_NAN__"); + Define(Defs, "__DBL_MANT_DIG__", "53"); + Define(Defs, "__DBL_MAX_10_EXP__", "308"); + Define(Defs, "__DBL_MAX_EXP__", "1024"); + Define(Defs, "__DBL_MAX__", "1.7976931348623157e+308"); + Define(Defs, "__DBL_MIN_10_EXP__", "(-307)"); + Define(Defs, "__DBL_MIN_EXP__", "(-1021)"); + Define(Defs, "__DBL_MIN__", "2.2250738585072014e-308"); + Define(Defs, "__DECIMAL_DIG__", "21"); + + // 80-bit Long double macros. + Define(Defs, "__LDBL_DENORM_MIN__", "3.64519953188247460253e-4951L"); + Define(Defs, "__LDBL_DIG__", "18"); + Define(Defs, "__LDBL_EPSILON__", "1.08420217248550443401e-19L"); + Define(Defs, "__LDBL_HAS_INFINITY__"); + Define(Defs, "__LDBL_HAS_QUIET_NAN__"); + Define(Defs, "__LDBL_MANT_DIG__", "64"); + Define(Defs, "__LDBL_MAX_10_EXP__", "4932"); + Define(Defs, "__LDBL_MAX_EXP__", "16384"); + Define(Defs, "__LDBL_MAX__", "1.18973149535723176502e+4932L"); + Define(Defs, "__LDBL_MIN_10_EXP__", "(-4931)"); + Define(Defs, "__LDBL_MIN_EXP__", "(-16381)"); + Define(Defs, "__LDBL_MIN__", "3.36210314311209350626e-4932L"); +} + +static const char* getI386VAListDeclaration() { + return "typedef char* __builtin_va_list;"; +} + +static const char* getX86_64VAListDeclaration() { + return + "typedef struct __va_list_tag {" + " unsigned gp_offset;" + " unsigned fp_offset;" + " void* overflow_arg_area;" + " void* reg_save_area;" + "} __builtin_va_list[1];"; +} + +static const char* getPPCVAListDeclaration() { + return + "typedef struct __va_list_tag {" + " unsigned char gpr;" + " unsigned char fpr;" + " unsigned short reserved;" + " void* overflow_arg_area;" + " void* reg_save_area;" + "} __builtin_va_list[1];"; +} + + +/// PPC builtin info. +namespace clang { +namespace PPC { + + static const Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS }, +#include "clang/AST/PPCBuiltins.def" + }; + + static void getBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) { + Records = BuiltinInfo; + NumRecords = LastTSBuiltin-Builtin::FirstTSBuiltin; + } + + static const char * const GCCRegNames[] = { + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "30", "31", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "30", "31", + "mq", "lr", "ctr", "ap", + "0", "1", "2", "3", "4", "5", "6", "7", + "xer", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "30", "31", + "vrsave", "vscr", + "spe_acc", "spefscr", + "sfp" + }; + + static void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + // While some of these aliases do map to different registers + // they still share the same register name. + { { "cc", "cr0", "fr0", "r0", "v0"}, "0" }, + { { "cr1", "fr1", "r1", "sp", "v1"}, "1" }, + { { "cr2", "fr2", "r2", "toc", "v2"}, "2" }, + { { "cr3", "fr3", "r3", "v3"}, "3" }, + { { "cr4", "fr4", "r4", "v4"}, "4" }, + { { "cr5", "fr5", "r5", "v5"}, "5" }, + { { "cr6", "fr6", "r6", "v6"}, "6" }, + { { "cr7", "fr7", "r7", "v7"}, "7" }, + { { "fr8", "r8", "v8"}, "8" }, + { { "fr9", "r9", "v9"}, "9" }, + { { "fr10", "r10", "v10"}, "10" }, + { { "fr11", "r11", "v11"}, "11" }, + { { "fr12", "r12", "v12"}, "12" }, + { { "fr13", "r13", "v13"}, "13" }, + { { "fr14", "r14", "v14"}, "14" }, + { { "fr15", "r15", "v15"}, "15" }, + { { "fr16", "r16", "v16"}, "16" }, + { { "fr17", "r17", "v17"}, "17" }, + { { "fr18", "r18", "v18"}, "18" }, + { { "fr19", "r19", "v19"}, "19" }, + { { "fr20", "r20", "v20"}, "20" }, + { { "fr21", "r21", "v21"}, "21" }, + { { "fr22", "r22", "v22"}, "22" }, + { { "fr23", "r23", "v23"}, "23" }, + { { "fr24", "r24", "v24"}, "24" }, + { { "fr25", "r25", "v25"}, "25" }, + { { "fr26", "r26", "v26"}, "26" }, + { { "fr27", "r27", "v27"}, "27" }, + { { "fr28", "r28", "v28"}, "28" }, + { { "fr29", "r29", "v29"}, "29" }, + { { "fr30", "r30", "v30"}, "30" }, + { { "fr31", "r31", "v31"}, "31" }, + }; + + static void getGCCRegAliases(const TargetInfo::GCCRegAlias *&Aliases, + unsigned &NumAliases) { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); + } + + static bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) { + switch (c) { + default: return false; + case 'O': // Zero + return true; + case 'b': // Base register + case 'f': // Floating point register + info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister); + return true; + } + } + + const char *getClobbers() { + return 0; + } + + const char *getTargetPrefix() { + return "ppc"; + } + +} // End namespace PPC + +/// X86 builtin info. +namespace X86 { + static const Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS }, +#include "clang/AST/X86Builtins.def" + }; + + static void getBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) { + Records = BuiltinInfo; + NumRecords = LastTSBuiltin-Builtin::FirstTSBuiltin; + } + + static const char *GCCRegNames[] = { + "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", + "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", + "argp", "flags", "fspr", "dirflag", "frame", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" + }; + + static void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + { { "al", "ah", "eax", "rax" }, "ax" }, + { { "bl", "bh", "ebx", "rbx" }, "bx" }, + { { "cl", "ch", "ecx", "rcx" }, "cx" }, + { { "dl", "dh", "edx", "rdx" }, "dx" }, + { { "esi", "rsi" }, "si" }, + { { "esp", "rsp" }, "sp" }, + { { "ebp", "rbp" }, "bp" }, + }; + + static void getGCCRegAliases(const TargetInfo::GCCRegAlias *&Aliases, + unsigned &NumAliases) { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); + } + + static bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) { + switch (c) { + default: return false; + case 'a': // eax. + case 'b': // ebx. + case 'c': // ecx. + case 'd': // edx. + case 'S': // esi. + case 'D': // edi. + case 'A': // edx:eax. + case 't': // top of floating point stack. + case 'u': // second from top of floating point stack. + case 'q': // a, b, c, d registers or any integer register in 64-bit. + case 'Z': // 32-bit integer constant for use with zero-extending x86_64 + // instructions. + case 'N': // unsigned 8-bit integer constant for use with in and out + // instructions. + info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister); + return true; + } + } + + static std::string convertConstraint(const char Constraint) { + switch (Constraint) { + case 'a': return std::string("{ax}"); + case 'b': return std::string("{bx}"); + case 'c': return std::string("{cx}"); + case 'd': return std::string("{dx}"); + case 'S': return std::string("{si}"); + case 'D': return std::string("{di}"); + case 't': // top of floating point stack. + return std::string("{st}"); + case 'u': // second from top of floating point stack. + return std::string("{st(1)}"); // second from top of floating point stack. + default: + return std::string(1, Constraint); + } + } + + const char *getClobbers() { + return "~{dirflag},~{fpsr},~{flags}"; + } + + const char *getTargetPrefix() { + return "x86"; + } + +} // End namespace X86 +} // end namespace clang. + +//===----------------------------------------------------------------------===// +// Specific target implementations. +//===----------------------------------------------------------------------===// + + +namespace { +class DarwinPPCTargetInfo : public DarwinTargetInfo { +public: + DarwinPPCTargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} + + virtual void getTargetDefines(std::vector<char> &Defines) const { + DarwinTargetInfo::getTargetDefines(Defines); + getPowerPCDefines(Defines, false); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + PPC::getBuiltins(Records, NumRecords); + } + virtual const char *getVAListDeclaration() const { + return getPPCVAListDeclaration(); + } + virtual const char *getTargetPrefix() const { + return PPC::getTargetPrefix(); + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + PPC::getGCCRegNames(Names, NumNames); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + PPC::getGCCRegAliases(Aliases, NumAliases); + } + virtual bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) const { + return PPC::validateAsmConstraint(c, info); + } + virtual const char *getClobbers() const { + return PPC::getClobbers(); + } +}; +} // end anonymous namespace. + +namespace { +class DarwinPPC64TargetInfo : public DarwinTargetInfo { +public: + DarwinPPC64TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} + + virtual void getTargetDefines(std::vector<char> &Defines) const { + DarwinTargetInfo::getTargetDefines(Defines); + getPowerPCDefines(Defines, true); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + PPC::getBuiltins(Records, NumRecords); + } + virtual const char *getVAListDeclaration() const { + return getPPCVAListDeclaration(); + } + virtual const char *getTargetPrefix() const { + return PPC::getTargetPrefix(); + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + PPC::getGCCRegNames(Names, NumNames); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + PPC::getGCCRegAliases(Aliases, NumAliases); + } + virtual bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) const { + return PPC::validateAsmConstraint(c, info); + } + virtual const char *getClobbers() const { + return PPC::getClobbers(); + } +}; +} // end anonymous namespace. + +namespace { +class DarwinI386TargetInfo : public DarwinTargetInfo { +public: + DarwinI386TargetInfo(const std::string& triple) : DarwinTargetInfo(triple) {} + + virtual void getTargetDefines(std::vector<char> &Defines) const { + DarwinTargetInfo::getTargetDefines(Defines); + getX86Defines(Defines, false); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + X86::getBuiltins(Records, NumRecords); + } + virtual const char *getVAListDeclaration() const { + return getI386VAListDeclaration(); + } + virtual const char *getTargetPrefix() const { + return X86::getTargetPrefix(); + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + X86::getGCCRegNames(Names, NumNames); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + X86::getGCCRegAliases(Aliases, NumAliases); + } + virtual bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) const { + return X86::validateAsmConstraint(c, info); + } + + virtual std::string convertConstraint(const char Constraint) const { + return X86::convertConstraint(Constraint); + } + + virtual const char *getClobbers() const { + return X86::getClobbers(); + } +}; +} // end anonymous namespace. + +namespace { +class DarwinX86_64TargetInfo : public DarwinTargetInfo { +public: + DarwinX86_64TargetInfo(const std::string& triple) :DarwinTargetInfo(triple) {} + + virtual void getTargetDefines(std::vector<char> &Defines) const { + DarwinTargetInfo::getTargetDefines(Defines); + getX86Defines(Defines, true); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + X86::getBuiltins(Records, NumRecords); + } + virtual const char *getVAListDeclaration() const { + return getX86_64VAListDeclaration(); + } + virtual const char *getTargetPrefix() const { + return X86::getTargetPrefix(); + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + X86::getGCCRegNames(Names, NumNames); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + X86::getGCCRegAliases(Aliases, NumAliases); + } + virtual bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) const { + return X86::validateAsmConstraint(c, info); + } + virtual std::string convertConstraint(const char Constraint) const { + return X86::convertConstraint(Constraint); + } + virtual const char *getClobbers() const { + return X86::getClobbers(); + } +}; +} // end anonymous namespace. + +namespace { +class SolarisSparcV8TargetInfo : public SolarisTargetInfo { +public: + SolarisSparcV8TargetInfo(const std::string& triple) : SolarisTargetInfo(triple) {} + + virtual void getTargetDefines(std::vector<char> &Defines) const { + SolarisTargetInfo::getTargetDefines(Defines); +// getSparcDefines(Defines, false); + Define(Defines, "__sparc"); + Define(Defines, "__sparcv8"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + PPC::getBuiltins(Records, NumRecords); + } + virtual const char *getVAListDeclaration() const { + return getPPCVAListDeclaration(); + } + virtual const char *getTargetPrefix() const { + return PPC::getTargetPrefix(); + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + PPC::getGCCRegNames(Names, NumNames); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + PPC::getGCCRegAliases(Aliases, NumAliases); + } + virtual bool validateAsmConstraint(char c, + TargetInfo::ConstraintInfo &info) const { + return PPC::validateAsmConstraint(c, info); + } + virtual const char *getClobbers() const { + return PPC::getClobbers(); + } +}; + +} // end anonymous namespace. + + +//===----------------------------------------------------------------------===// +// Driver code +//===----------------------------------------------------------------------===// + +static inline bool IsX86(const std::string& TT) { + return (TT.size() >= 5 && TT[0] == 'i' && TT[2] == '8' && TT[3] == '6' && + TT[4] == '-' && TT[1] - '3' < 6); +} + +/// CreateTargetInfo - Return the target info object for the specified target +/// triple. +TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { + if (T.find("ppc-") == 0 || T.find("powerpc-") == 0) + return new DarwinPPCTargetInfo(T); + + if (T.find("ppc64-") == 0 || T.find("powerpc64-") == 0) + return new DarwinPPC64TargetInfo(T); + + if (T.find("sparc-") == 0) + return new SolarisSparcV8TargetInfo(T); // ugly hack + + if (T.find("x86_64-") == 0) + return new DarwinX86_64TargetInfo(T); + + if (IsX86(T)) + return new DarwinI386TargetInfo(T); + + return NULL; +} + diff --git a/clang/lib/Basic/TokenKinds.cpp b/clang/lib/Basic/TokenKinds.cpp new file mode 100644 index 00000000000..bde8a5598b4 --- /dev/null +++ b/clang/lib/Basic/TokenKinds.cpp @@ -0,0 +1,29 @@ +//===--- TokenKinds.cpp - Token Kinds Support -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the TokenKind enum and support functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TokenKinds.h" + +#include <cassert> +using namespace clang; + +static const char * const TokNames[] = { +#define TOK(X) #X, +#define KEYWORD(X,Y) #X, +#include "clang/Basic/TokenKinds.def" + 0 +}; + +const char *tok::getTokenName(enum TokenKind Kind) { + assert(Kind < tok::NUM_TOKENS); + return TokNames[Kind]; +} |