diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Basic')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Builtins.cpp | 95 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/CMakeLists.txt | 36 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/ConvertUTF.c | 547 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp | 1322 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/FileManager.cpp | 398 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp | 402 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Makefile | 35 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp | 124 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp | 1288 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp | 384 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Targets.cpp | 2476 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/TokenKinds.cpp | 39 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Version.cpp | 76 |
13 files changed, 7222 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp new file mode 100644 index 0000000..1a32937 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp @@ -0,0 +1,95 @@ +//===--- Builtins.cpp - Builtin function implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements various things for builtin functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Builtins.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/TargetInfo.h" +using namespace clang; + +static const Builtin::Info BuiltinInfo[] = { + { "not a builtin function", 0, 0, 0, false }, +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false }, +#include "clang/Basic/Builtins.def" +}; + +const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const { + if (ID < Builtin::FirstTSBuiltin) + return BuiltinInfo[ID]; + assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!"); + return TSRecords[ID - Builtin::FirstTSBuiltin]; +} + +Builtin::Context::Context(const TargetInfo &Target) { + // Get the target specific builtins from the target. + TSRecords = 0; + NumTSRecords = 0; + Target.getTargetBuiltins(TSRecords, NumTSRecords); +} + +/// InitializeBuiltins - Mark the identifiers for all the builtins with their +/// appropriate builtin ID # and mark any non-portable builtin identifiers as +/// such. +void Builtin::Context::InitializeBuiltins(IdentifierTable &Table, + bool NoBuiltins) { + // Step #1: mark all target-independent builtins with their ID's. + for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) + if (!BuiltinInfo[i].Suppressed && + (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) + Table.get(BuiltinInfo[i].Name).setBuiltinID(i); + + // Step #2: Register target-specific builtins. + for (unsigned i = 0, e = NumTSRecords; i != e; ++i) + if (!TSRecords[i].Suppressed && + (!NoBuiltins || + (TSRecords[i].Attributes && + !strchr(TSRecords[i].Attributes, 'f')))) + Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); +} + +void +Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names, + bool NoBuiltins) { + // Final all target-independent names + for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) + if (!BuiltinInfo[i].Suppressed && + (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) + Names.push_back(BuiltinInfo[i].Name); + + // Find target-specific names. + for (unsigned i = 0, e = NumTSRecords; i != e; ++i) + if (!TSRecords[i].Suppressed && + (!NoBuiltins || + (TSRecords[i].Attributes && + !strchr(TSRecords[i].Attributes, 'f')))) + Names.push_back(TSRecords[i].Name); +} + +bool +Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, + bool &HasVAListArg) { + const char *Printf = strpbrk(GetRecord(ID).Attributes, "pP"); + if (!Printf) + return false; + + HasVAListArg = (*Printf == 'P'); + + ++Printf; + assert(*Printf == ':' && "p or P specifier must have be followed by a ':'"); + ++Printf; + + assert(strchr(Printf, ':') && "printf specifier must end with a ':'"); + FormatIdx = strtol(Printf, 0, 10); + return true; +} + diff --git a/contrib/llvm/tools/clang/lib/Basic/CMakeLists.txt b/contrib/llvm/tools/clang/lib/Basic/CMakeLists.txt new file mode 100644 index 0000000..1a89acc --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/CMakeLists.txt @@ -0,0 +1,36 @@ +set(LLVM_NO_RTTI 1) + +add_clang_library(clangBasic + Builtins.cpp + ConvertUTF.c + Diagnostic.cpp + FileManager.cpp + IdentifierTable.cpp + SourceLocation.cpp + SourceManager.cpp + TargetInfo.cpp + Targets.cpp + TokenKinds.cpp + Version.cpp + ) + +# Determine Subversion revision. +# FIXME: This only gets updated when CMake is run, so this revision number +# may be out-of-date! +find_package(Subversion) +if (Subversion_FOUND AND EXISTS "${CLANG_SOURCE_DIR}/.svn") + Subversion_WC_INFO(${CLANG_SOURCE_DIR} CLANG) + set_source_files_properties(Version.cpp + PROPERTIES COMPILE_DEFINITIONS "SVN_REVISION=\"${CLANG_WC_REVISION}\"") +endif() + +add_dependencies(clangBasic + ClangDiagnosticAnalysis + ClangDiagnosticAST + ClangDiagnosticCommon + ClangDiagnosticDriver + ClangDiagnosticFrontend + ClangDiagnosticGroups + ClangDiagnosticLex + ClangDiagnosticParse + ClangDiagnosticSema) diff --git a/contrib/llvm/tools/clang/lib/Basic/ConvertUTF.c b/contrib/llvm/tools/clang/lib/Basic/ConvertUTF.c new file mode 100644 index 0000000..124e386 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/ConvertUTF.c @@ -0,0 +1,547 @@ +/*===--- ConvertUTF.c - Universal Character Names conversions ---------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *===------------------------------------------------------------------------=*/ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Source code file. + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Sept 2001: fixed const & error conditions per + mods suggested by S. Parent & A. Lillich. + June 2002: Tim Dodd added detection and handling of incomplete + source sequences, enhanced error detection, added casts + to eliminate compiler warnings. + July 2003: slight mods to back out aggressive FFFE detection. + Jan 2004: updated switches in from-UTF8 conversions. + Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + + See the header file "ConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "clang/Basic/ConvertUTF.h" +#ifdef CVTUTF_DEBUG +#include <stdio.h> +#endif + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +#define false 0 +#define true 1 + +/* --------------------------------------------------------------------- */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. + */ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. + * Constants have been gathered. Loops & conditionals have been removed as + * much as possible for efficiency, in favor of drop-through switches. + * (See "Note A" at the bottom of the file for equivalent code.) + * If your compiler supports it, the "isLegalUTF8" call can be turned + * into an inline function. + */ + +#ifdef CLANG_NEEDS_THESE_ONE_DAY + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG +if (result == sourceIllegal) { + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); +} +#endif + return result; +} +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} +#endif + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- + + Note A. + The fall-through switches in UTF-8 reading code save a + temp variable, some decrements & conditionals. The switches + are equivalent to the following loop: + { + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); + } + In UTF-8 writing code, the switches on "bytesToWrite" are + similarly unrolled loops. + + --------------------------------------------------------------------- */ diff --git a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp new file mode 100644 index 0000000..2fd985f --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp @@ -0,0 +1,1322 @@ +//===--- 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/AST/ASTDiagnostic.h" +#include "clang/Analysis/AnalysisDiagnostic.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/LexDiagnostic.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +#include <vector> +#include <map> +#include <cstring> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Builtin Diagnostic information +//===----------------------------------------------------------------------===// + +// Diagnostic classes. +enum { + CLASS_NOTE = 0x01, + CLASS_WARNING = 0x02, + CLASS_EXTENSION = 0x03, + CLASS_ERROR = 0x04 +}; + +struct StaticDiagInfoRec { + unsigned short DiagID; + unsigned Mapping : 3; + unsigned Class : 3; + bool SFINAE : 1; + unsigned Category : 5; + + const char *Description; + const char *OptionGroup; + + bool operator<(const StaticDiagInfoRec &RHS) const { + return DiagID < RHS.DiagID; + } + bool operator>(const StaticDiagInfoRec &RHS) const { + return DiagID > RHS.DiagID; + } +}; + +static const StaticDiagInfoRec StaticDiagInfo[] = { +#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE, CATEGORY) \ + { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, CATEGORY, DESC, GROUP }, +#include "clang/Basic/DiagnosticCommonKinds.inc" +#include "clang/Basic/DiagnosticDriverKinds.inc" +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#include "clang/Basic/DiagnosticLexKinds.inc" +#include "clang/Basic/DiagnosticParseKinds.inc" +#include "clang/Basic/DiagnosticASTKinds.inc" +#include "clang/Basic/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.inc" + { 0, 0, 0, 0, 0, 0, 0} +}; +#undef DIAG + +/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID, +/// or null if the ID is invalid. +static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { + unsigned NumDiagEntries = sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1; + + // If assertions are enabled, verify that the StaticDiagInfo array is sorted. +#ifndef NDEBUG + static bool IsFirst = true; + if (IsFirst) { + for (unsigned i = 1; i != NumDiagEntries; ++i) { + assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID && + "Diag ID conflict, the enums at the start of clang::diag (in " + "Diagnostic.h) probably need to be increased"); + + assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] && + "Improperly sorted diag info"); + } + IsFirst = false; + } +#endif + + // Search the diagnostic table with a binary search. + StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0 }; + + const StaticDiagInfoRec *Found = + std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find); + if (Found == StaticDiagInfo + NumDiagEntries || + Found->DiagID != DiagID) + return 0; + + return Found; +} + +static unsigned GetDefaultDiagMapping(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->Mapping; + return diag::MAP_FATAL; +} + +/// getWarningOptionForDiag - Return the lowest-level warning option that +/// enables the specified diagnostic. If there is no -Wfoo flag that controls +/// the diagnostic, this returns null. +const char *Diagnostic::getWarningOptionForDiag(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->OptionGroup; + return 0; +} + +/// getWarningOptionForDiag - Return the category number that a specified +/// DiagID belongs to, or 0 if no category. +unsigned Diagnostic::getCategoryNumberForDiag(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->Category; + return 0; +} + +/// getCategoryNameFromID - Given a category ID, return the name of the +/// category, an empty string if CategoryID is zero, or null if CategoryID is +/// invalid. +const char *Diagnostic::getCategoryNameFromID(unsigned CategoryID) { + // Second the table of options, sorted by name for fast binary lookup. + static const char *CategoryNameTable[] = { +#define GET_CATEGORY_TABLE +#define CATEGORY(X) X, +#include "clang/Basic/DiagnosticGroups.inc" +#undef GET_CATEGORY_TABLE + "<<END>>" + }; + static const size_t CategoryNameTableSize = + sizeof(CategoryNameTable) / sizeof(CategoryNameTable[0])-1; + + if (CategoryID >= CategoryNameTableSize) return 0; + return CategoryNameTable[CategoryID]; +} + + + +Diagnostic::SFINAEResponse +Diagnostic::getDiagnosticSFINAEResponse(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) { + if (!Info->SFINAE) + return SFINAE_Report; + + if (Info->Class == CLASS_ERROR) + return SFINAE_SubstitutionFailure; + + // Suppress notes, warnings, and extensions; + return SFINAE_Suppress; + } + + return SFINAE_Report; +} + +/// getDiagClass - Return the class field of the diagnostic. +/// +static unsigned getBuiltinDiagClass(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->Class; + return ~0U; +} + +//===----------------------------------------------------------------------===// +// 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_UPPER_LIMIT < DiagInfo.size() && + "Invalid diagnosic ID"); + return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second.c_str(); + } + + /// getLevel - Return the level of the specified custom diagnostic. + Diagnostic::Level getLevel(unsigned DiagID) const { + assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() && + "Invalid diagnosic ID"); + return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first; + } + + unsigned getOrCreateDiagID(Diagnostic::Level L, llvm::StringRef Message, + Diagnostic &Diags) { + 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_UPPER_LIMIT; + DiagIDs.insert(std::make_pair(D, ID)); + DiagInfo.push_back(D); + return ID; + } + }; + + } // end diag namespace +} // end clang namespace + + +//===----------------------------------------------------------------------===// +// Common Diagnostic implementation +//===----------------------------------------------------------------------===// + +static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT, + const char *Modifier, unsigned ML, + const char *Argument, unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + llvm::SmallVectorImpl<char> &Output, + void *Cookie) { + const char *Str = "<can't format argument>"; + Output.append(Str, Str+strlen(Str)); +} + + +Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { + AllExtensionsSilenced = 0; + IgnoreAllWarnings = false; + WarningsAsErrors = false; + ErrorsAsFatal = false; + SuppressSystemWarnings = false; + SuppressAllDiagnostics = false; + ExtBehavior = Ext_Ignore; + + ErrorOccurred = false; + FatalErrorOccurred = false; + ErrorLimit = 0; + TemplateBacktraceLimit = 0; + + NumWarnings = 0; + NumErrors = 0; + NumErrorsSuppressed = 0; + CustomDiagInfo = 0; + CurDiagID = ~0U; + LastDiagLevel = Ignored; + + ArgToStringFn = DummyArgToStringFn; + ArgToStringCookie = 0; + + DelayedDiagID = 0; + + // Set all mappings to 'unset'. + DiagMappings BlankDiags(diag::DIAG_UPPER_LIMIT/2, 0); + DiagMappingsStack.push_back(BlankDiags); +} + +Diagnostic::~Diagnostic() { + delete CustomDiagInfo; +} + + +void Diagnostic::pushMappings() { + // Avoids undefined behavior when the stack has to resize. + DiagMappingsStack.reserve(DiagMappingsStack.size() + 1); + DiagMappingsStack.push_back(DiagMappingsStack.back()); +} + +bool Diagnostic::popMappings() { + if (DiagMappingsStack.size() == 1) + return false; + + DiagMappingsStack.pop_back(); + return true; +} + +/// 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, llvm::StringRef Message) { + if (CustomDiagInfo == 0) + CustomDiagInfo = new diag::CustomDiagInfo(); + return CustomDiagInfo->getOrCreateDiagID(L, Message, *this); +} + + +/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic +/// level of the specified diagnostic ID is a Warning or Extension. +/// This only works on builtin diagnostics, not custom ones, and is not legal to +/// call on NOTEs. +bool Diagnostic::isBuiltinWarningOrExtension(unsigned DiagID) { + return DiagID < diag::DIAG_UPPER_LIMIT && + getBuiltinDiagClass(DiagID) != CLASS_ERROR; +} + +/// \brief Determine whether the given built-in diagnostic ID is a +/// Note. +bool Diagnostic::isBuiltinNote(unsigned DiagID) { + return DiagID < diag::DIAG_UPPER_LIMIT && + getBuiltinDiagClass(DiagID) == CLASS_NOTE; +} + +/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic +/// ID is for an extension of some sort. This also returns EnabledByDefault, +/// which is set to indicate whether the diagnostic is ignored by default (in +/// which case -pedantic enables it) or treated as a warning/error by default. +/// +bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID, + bool &EnabledByDefault) { + if (DiagID >= diag::DIAG_UPPER_LIMIT || + getBuiltinDiagClass(DiagID) != CLASS_EXTENSION) + return false; + + EnabledByDefault = StaticDiagInfo[DiagID].Mapping != diag::MAP_IGNORE; + return true; +} + + +/// getDescription - Given a diagnostic ID, return a description of the +/// issue. +const char *Diagnostic::getDescription(unsigned DiagID) const { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->Description; + return CustomDiagInfo->getDescription(DiagID); +} + +void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1, + llvm::StringRef Arg2) { + if (DelayedDiagID) + return; + + DelayedDiagID = DiagID; + DelayedDiagArg1 = Arg1.str(); + DelayedDiagArg2 = Arg2.str(); +} + +void Diagnostic::ReportDelayed() { + Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2; + DelayedDiagID = 0; + DelayedDiagArg1.clear(); + DelayedDiagArg2.clear(); +} + +/// 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::DIAG_UPPER_LIMIT) + return CustomDiagInfo->getLevel(DiagID); + + unsigned DiagClass = getBuiltinDiagClass(DiagID); + assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!"); + return getDiagnosticLevel(DiagID, DiagClass); +} + +/// 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, unsigned DiagClass) const { + // Specific non-error diagnostics may be mapped to various levels from ignored + // to error. Errors can only be mapped to fatal. + Diagnostic::Level Result = Diagnostic::Fatal; + + // Get the mapping information, if unset, compute it lazily. + unsigned MappingInfo = getDiagnosticMappingInfo((diag::kind)DiagID); + if (MappingInfo == 0) { + MappingInfo = GetDefaultDiagMapping(DiagID); + setDiagnosticMappingInternal(DiagID, MappingInfo, false); + } + + switch (MappingInfo & 7) { + default: assert(0 && "Unknown mapping!"); + case diag::MAP_IGNORE: + // Ignore this, unless this is an extension diagnostic and we're mapping + // them onto warnings or errors. + if (!isBuiltinExtensionDiag(DiagID) || // Not an extension + ExtBehavior == Ext_Ignore || // Extensions ignored anyway + (MappingInfo & 8) != 0) // User explicitly mapped it. + return Diagnostic::Ignored; + Result = Diagnostic::Warning; + if (ExtBehavior == Ext_Error) Result = Diagnostic::Error; + if (Result == Diagnostic::Error && ErrorsAsFatal) + Result = Diagnostic::Fatal; + break; + case diag::MAP_ERROR: + Result = Diagnostic::Error; + if (ErrorsAsFatal) + Result = Diagnostic::Fatal; + break; + case diag::MAP_FATAL: + Result = Diagnostic::Fatal; + break; + case diag::MAP_WARNING: + // If warnings are globally mapped to ignore or error, do it. + if (IgnoreAllWarnings) + return Diagnostic::Ignored; + + Result = Diagnostic::Warning; + + // If this is an extension diagnostic and we're in -pedantic-error mode, and + // if the user didn't explicitly map it, upgrade to an error. + if (ExtBehavior == Ext_Error && + (MappingInfo & 8) == 0 && + isBuiltinExtensionDiag(DiagID)) + Result = Diagnostic::Error; + + if (WarningsAsErrors) + Result = Diagnostic::Error; + if (Result == Diagnostic::Error && ErrorsAsFatal) + Result = Diagnostic::Fatal; + break; + + case diag::MAP_WARNING_NO_WERROR: + // Diagnostics specified with -Wno-error=foo should be set to warnings, but + // not be adjusted by -Werror or -pedantic-errors. + Result = Diagnostic::Warning; + + // If warnings are globally mapped to ignore or error, do it. + if (IgnoreAllWarnings) + return Diagnostic::Ignored; + + break; + + case diag::MAP_ERROR_NO_WFATAL: + // Diagnostics specified as -Wno-fatal-error=foo should be errors, but + // unaffected by -Wfatal-errors. + Result = Diagnostic::Error; + break; + } + + // Okay, we're about to return this as a "diagnostic to emit" one last check: + // if this is any sort of extension warning, and if we're in an __extension__ + // block, silence it. + if (AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID)) + return Diagnostic::Ignored; + + return Result; +} + +struct WarningOption { + const char *Name; + const short *Members; + const short *SubGroups; +}; + +#define GET_DIAG_ARRAYS +#include "clang/Basic/DiagnosticGroups.inc" +#undef GET_DIAG_ARRAYS + +// Second the table of options, sorted by name for fast binary lookup. +static const WarningOption OptionTable[] = { +#define GET_DIAG_TABLE +#include "clang/Basic/DiagnosticGroups.inc" +#undef GET_DIAG_TABLE +}; +static const size_t OptionTableSize = +sizeof(OptionTable) / sizeof(OptionTable[0]); + +static bool WarningOptionCompare(const WarningOption &LHS, + const WarningOption &RHS) { + return strcmp(LHS.Name, RHS.Name) < 0; +} + +static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping, + Diagnostic &Diags) { + // Option exists, poke all the members of its diagnostic set. + if (const short *Member = Group->Members) { + for (; *Member != -1; ++Member) + Diags.setDiagnosticMapping(*Member, Mapping); + } + + // Enable/disable all subgroups along with this one. + if (const short *SubGroups = Group->SubGroups) { + for (; *SubGroups != (short)-1; ++SubGroups) + MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Diags); + } +} + +/// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g. +/// "unknown-pragmas" to have the specified mapping. This returns true and +/// ignores the request if "Group" was unknown, false otherwise. +bool Diagnostic::setDiagnosticGroupMapping(const char *Group, + diag::Mapping Map) { + + WarningOption Key = { Group, 0, 0 }; + const WarningOption *Found = + std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key, + WarningOptionCompare); + if (Found == OptionTable + OptionTableSize || + strcmp(Found->Name, Group) != 0) + return true; // Option not found. + + MapGroupMembers(Found, Map, *this); + return false; +} + + +/// ProcessDiag - This is the method used to report a diagnostic that is +/// finally fully formed. +bool Diagnostic::ProcessDiag() { + DiagnosticInfo Info(this); + + if (SuppressAllDiagnostics) + return false; + + // Figure out the diagnostic level of this message. + Diagnostic::Level DiagLevel; + unsigned DiagID = Info.getID(); + + // ShouldEmitInSystemHeader - True if this diagnostic should be produced even + // in a system header. + bool ShouldEmitInSystemHeader; + + if (DiagID >= diag::DIAG_UPPER_LIMIT) { + // Handle custom diagnostics, which cannot be mapped. + DiagLevel = CustomDiagInfo->getLevel(DiagID); + + // Custom diagnostics always are emitted in system headers. + ShouldEmitInSystemHeader = true; + } else { + // Get the class of the diagnostic. If this is a NOTE, map it onto whatever + // the diagnostic level was for the previous diagnostic so that it is + // filtered the same as the previous diagnostic. + unsigned DiagClass = getBuiltinDiagClass(DiagID); + if (DiagClass == CLASS_NOTE) { + DiagLevel = Diagnostic::Note; + ShouldEmitInSystemHeader = false; // extra consideration is needed + } else { + // If this is not an error and we are in a system header, we ignore it. + // Check the original Diag ID here, because we also want to ignore + // extensions and warnings in -Werror and -pedantic-errors modes, which + // *map* warnings/extensions to errors. + ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR; + + DiagLevel = getDiagnosticLevel(DiagID, DiagClass); + } + } + + if (DiagLevel != Diagnostic::Note) { + // Record that a fatal error occurred only when we see a second + // non-note diagnostic. This allows notes to be attached to the + // fatal error, but suppresses any diagnostics that follow those + // notes. + if (LastDiagLevel == Diagnostic::Fatal) + FatalErrorOccurred = true; + + LastDiagLevel = DiagLevel; + } + + // If a fatal error has already been emitted, silence all subsequent + // diagnostics. + if (FatalErrorOccurred) { + if (DiagLevel >= Diagnostic::Error) { + ++NumErrors; + ++NumErrorsSuppressed; + } + + return false; + } + + // If the client doesn't care about this message, don't issue it. If this is + // a note and the last real diagnostic was ignored, ignore it too. + if (DiagLevel == Diagnostic::Ignored || + (DiagLevel == Diagnostic::Note && LastDiagLevel == Diagnostic::Ignored)) + return false; + + // If this diagnostic is in a system header and is not a clang error, suppress + // it. + if (SuppressSystemWarnings && !ShouldEmitInSystemHeader && + Info.getLocation().isValid() && + Info.getLocation().getInstantiationLoc().isInSystemHeader() && + (DiagLevel != Diagnostic::Note || LastDiagLevel == Diagnostic::Ignored)) { + LastDiagLevel = Diagnostic::Ignored; + return false; + } + + if (DiagLevel >= Diagnostic::Error) { + ErrorOccurred = true; + ++NumErrors; + + // If we've emitted a lot of errors, emit a fatal error after it to stop a + // flood of bogus errors. + if (ErrorLimit && NumErrors >= ErrorLimit && + DiagLevel == Diagnostic::Error) + SetDelayedDiagnostic(diag::fatal_too_many_errors); + } + + // Finally, report it. + Client->HandleDiagnostic(DiagLevel, Info); + if (Client->IncludeInDiagnosticCounts()) { + if (DiagLevel == Diagnostic::Warning) + ++NumWarnings; + } + + CurDiagID = ~0U; + + return true; +} + +bool DiagnosticBuilder::Emit() { + // If DiagObj is null, then its soul was stolen by the copy ctor + // or the user called Emit(). + if (DiagObj == 0) return false; + + // When emitting diagnostics, we set the final argument count into + // the Diagnostic object. + DiagObj->NumDiagArgs = NumArgs; + DiagObj->NumDiagRanges = NumRanges; + DiagObj->NumFixItHints = NumFixItHints; + + // Process the diagnostic, sending the accumulated information to the + // DiagnosticClient. + bool Emitted = DiagObj->ProcessDiag(); + + // Clear out the current diagnostic object. + unsigned DiagID = DiagObj->CurDiagID; + DiagObj->Clear(); + + // If there was a delayed diagnostic, emit it now. + if (DiagObj->DelayedDiagID && DiagObj->DelayedDiagID != DiagID) + DiagObj->ReportDelayed(); + + // This diagnostic is dead. + DiagObj = 0; + + return Emitted; +} + + +DiagnosticClient::~DiagnosticClient() {} + + +/// ModifierIs - Return true if the specified modifier matches specified string. +template <std::size_t StrLen> +static bool ModifierIs(const char *Modifier, unsigned ModifierLen, + const char (&Str)[StrLen]) { + return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1); +} + +/// ScanForward - Scans forward, looking for the given character, skipping +/// nested clauses and escaped characters. +static const char *ScanFormat(const char *I, const char *E, char Target) { + unsigned Depth = 0; + + for ( ; I != E; ++I) { + if (Depth == 0 && *I == Target) return I; + if (Depth != 0 && *I == '}') Depth--; + + if (*I == '%') { + I++; + if (I == E) break; + + // Escaped characters get implicitly skipped here. + + // Format specifier. + if (!isdigit(*I) && !ispunct(*I)) { + for (I++; I != E && !isdigit(*I) && *I != '{'; I++) ; + if (I == E) break; + if (*I == '{') + Depth++; + } + } + } + return E; +} + +/// HandleSelectModifier - Handle the integer 'select' modifier. This is used +/// like this: %select{foo|bar|baz}2. This means that the integer argument +/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'. +/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'. +/// This is very useful for certain classes of variant diagnostics. +static void HandleSelectModifier(const DiagnosticInfo &DInfo, unsigned ValNo, + const char *Argument, unsigned ArgumentLen, + llvm::SmallVectorImpl<char> &OutStr) { + const char *ArgumentEnd = Argument+ArgumentLen; + + // Skip over 'ValNo' |'s. + while (ValNo) { + const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|'); + assert(NextVal != ArgumentEnd && "Value for integer select modifier was" + " larger than the number of options in the diagnostic string!"); + Argument = NextVal+1; // Skip this string. + --ValNo; + } + + // Get the end of the value. This is either the } or the |. + const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|'); + + // Recursively format the result of the select clause into the output string. + DInfo.FormatDiagnostic(Argument, EndPtr, OutStr); +} + +/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the +/// letter 's' to the string if the value is not 1. This is used in cases like +/// this: "you idiot, you have %4 parameter%s4!". +static void HandleIntegerSModifier(unsigned ValNo, + llvm::SmallVectorImpl<char> &OutStr) { + if (ValNo != 1) + OutStr.push_back('s'); +} + +/// HandleOrdinalModifier - Handle the integer 'ord' modifier. This +/// prints the ordinal form of the given integer, with 1 corresponding +/// to the first ordinal. Currently this is hard-coded to use the +/// English form. +static void HandleOrdinalModifier(unsigned ValNo, + llvm::SmallVectorImpl<char> &OutStr) { + assert(ValNo != 0 && "ValNo must be strictly positive!"); + + llvm::raw_svector_ostream Out(OutStr); + + // We could use text forms for the first N ordinals, but the numeric + // forms are actually nicer in diagnostics because they stand out. + Out << ValNo; + + // It is critically important that we do this perfectly for + // user-written sequences with over 100 elements. + switch (ValNo % 100) { + case 11: + case 12: + case 13: + Out << "th"; return; + default: + switch (ValNo % 10) { + case 1: Out << "st"; return; + case 2: Out << "nd"; return; + case 3: Out << "rd"; return; + default: Out << "th"; return; + } + } +} + + +/// PluralNumber - Parse an unsigned integer and advance Start. +static unsigned PluralNumber(const char *&Start, const char *End) { + // Programming 101: Parse a decimal number :-) + unsigned Val = 0; + while (Start != End && *Start >= '0' && *Start <= '9') { + Val *= 10; + Val += *Start - '0'; + ++Start; + } + return Val; +} + +/// TestPluralRange - Test if Val is in the parsed range. Modifies Start. +static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) { + if (*Start != '[') { + unsigned Ref = PluralNumber(Start, End); + return Ref == Val; + } + + ++Start; + unsigned Low = PluralNumber(Start, End); + assert(*Start == ',' && "Bad plural expression syntax: expected ,"); + ++Start; + unsigned High = PluralNumber(Start, End); + assert(*Start == ']' && "Bad plural expression syntax: expected )"); + ++Start; + return Low <= Val && Val <= High; +} + +/// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier. +static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) { + // Empty condition? + if (*Start == ':') + return true; + + while (1) { + char C = *Start; + if (C == '%') { + // Modulo expression + ++Start; + unsigned Arg = PluralNumber(Start, End); + assert(*Start == '=' && "Bad plural expression syntax: expected ="); + ++Start; + unsigned ValMod = ValNo % Arg; + if (TestPluralRange(ValMod, Start, End)) + return true; + } else { + assert((C == '[' || (C >= '0' && C <= '9')) && + "Bad plural expression syntax: unexpected character"); + // Range expression + if (TestPluralRange(ValNo, Start, End)) + return true; + } + + // Scan for next or-expr part. + Start = std::find(Start, End, ','); + if (Start == End) + break; + ++Start; + } + return false; +} + +/// HandlePluralModifier - Handle the integer 'plural' modifier. This is used +/// for complex plural forms, or in languages where all plurals are complex. +/// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are +/// conditions that are tested in order, the form corresponding to the first +/// that applies being emitted. The empty condition is always true, making the +/// last form a default case. +/// Conditions are simple boolean expressions, where n is the number argument. +/// Here are the rules. +/// condition := expression | empty +/// empty := -> always true +/// expression := numeric [',' expression] -> logical or +/// numeric := range -> true if n in range +/// | '%' number '=' range -> true if n % number in range +/// range := number +/// | '[' number ',' number ']' -> ranges are inclusive both ends +/// +/// Here are some examples from the GNU gettext manual written in this form: +/// English: +/// {1:form0|:form1} +/// Latvian: +/// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0} +/// Gaeilge: +/// {1:form0|2:form1|:form2} +/// Romanian: +/// {1:form0|0,%100=[1,19]:form1|:form2} +/// Lithuanian: +/// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1} +/// Russian (requires repeated form): +/// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2} +/// Slovak +/// {1:form0|[2,4]:form1|:form2} +/// Polish (requires repeated form): +/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2} +static void HandlePluralModifier(unsigned ValNo, + const char *Argument, unsigned ArgumentLen, + llvm::SmallVectorImpl<char> &OutStr) { + const char *ArgumentEnd = Argument + ArgumentLen; + while (1) { + assert(Argument < ArgumentEnd && "Plural expression didn't match."); + const char *ExprEnd = Argument; + while (*ExprEnd != ':') { + assert(ExprEnd != ArgumentEnd && "Plural missing expression end"); + ++ExprEnd; + } + if (EvalPluralExpr(ValNo, Argument, ExprEnd)) { + Argument = ExprEnd + 1; + ExprEnd = ScanFormat(Argument, ArgumentEnd, '|'); + OutStr.append(Argument, ExprEnd); + return; + } + Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1; + } +} + + +/// FormatDiagnostic - Format this diagnostic into a string, substituting the +/// formal arguments into the %0 slots. The result is appended onto the Str +/// array. +void DiagnosticInfo:: +FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const { + const char *DiagStr = getDiags()->getDescription(getID()); + const char *DiagEnd = DiagStr+strlen(DiagStr); + + FormatDiagnostic(DiagStr, DiagEnd, OutStr); +} + +void DiagnosticInfo:: +FormatDiagnostic(const char *DiagStr, const char *DiagEnd, + llvm::SmallVectorImpl<char> &OutStr) const { + + /// FormattedArgs - Keep track of all of the arguments formatted by + /// ConvertArgToString and pass them into subsequent calls to + /// ConvertArgToString, allowing the implementation to avoid redundancies in + /// obvious cases. + llvm::SmallVector<Diagnostic::ArgumentValue, 8> FormattedArgs; + + while (DiagStr != DiagEnd) { + if (DiagStr[0] != '%') { + // Append non-%0 substrings to Str if we have one. + const char *StrEnd = std::find(DiagStr, DiagEnd, '%'); + OutStr.append(DiagStr, StrEnd); + DiagStr = StrEnd; + continue; + } else if (ispunct(DiagStr[1])) { + OutStr.push_back(DiagStr[1]); // %% -> %. + DiagStr += 2; + continue; + } + + // Skip the %. + ++DiagStr; + + // This must be a placeholder for a diagnostic argument. The format for a + // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0". + // The digit is a number from 0-9 indicating which argument this comes from. + // The modifier is a string of digits from the set [-a-z]+, arguments is a + // brace enclosed string. + const char *Modifier = 0, *Argument = 0; + unsigned ModifierLen = 0, ArgumentLen = 0; + + // Check to see if we have a modifier. If so eat it. + if (!isdigit(DiagStr[0])) { + Modifier = DiagStr; + while (DiagStr[0] == '-' || + (DiagStr[0] >= 'a' && DiagStr[0] <= 'z')) + ++DiagStr; + ModifierLen = DiagStr-Modifier; + + // If we have an argument, get it next. + if (DiagStr[0] == '{') { + ++DiagStr; // Skip {. + Argument = DiagStr; + + DiagStr = ScanFormat(DiagStr, DiagEnd, '}'); + assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!"); + ArgumentLen = DiagStr-Argument; + ++DiagStr; // Skip }. + } + } + + assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic"); + unsigned ArgNo = *DiagStr++ - '0'; + + Diagnostic::ArgumentKind Kind = getArgKind(ArgNo); + + switch (Kind) { + // ---- STRINGS ---- + case Diagnostic::ak_std_string: { + const std::string &S = getArgStdStr(ArgNo); + assert(ModifierLen == 0 && "No modifiers for strings yet"); + OutStr.append(S.begin(), S.end()); + break; + } + case Diagnostic::ak_c_string: { + const char *S = getArgCStr(ArgNo); + assert(ModifierLen == 0 && "No modifiers for strings yet"); + + // Don't crash if get passed a null pointer by accident. + if (!S) + S = "(null)"; + + OutStr.append(S, S + strlen(S)); + break; + } + // ---- INTEGERS ---- + case Diagnostic::ak_sint: { + int Val = getArgSInt(ArgNo); + + if (ModifierIs(Modifier, ModifierLen, "select")) { + HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen, OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "s")) { + HandleIntegerSModifier(Val, OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "plural")) { + HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) { + HandleOrdinalModifier((unsigned)Val, OutStr); + } else { + assert(ModifierLen == 0 && "Unknown integer modifier"); + llvm::raw_svector_ostream(OutStr) << Val; + } + break; + } + case Diagnostic::ak_uint: { + unsigned Val = getArgUInt(ArgNo); + + if (ModifierIs(Modifier, ModifierLen, "select")) { + HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "s")) { + HandleIntegerSModifier(Val, OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "plural")) { + HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) { + HandleOrdinalModifier(Val, OutStr); + } else { + assert(ModifierLen == 0 && "Unknown integer modifier"); + llvm::raw_svector_ostream(OutStr) << Val; + } + break; + } + // ---- NAMES and TYPES ---- + case Diagnostic::ak_identifierinfo: { + const IdentifierInfo *II = getArgIdentifier(ArgNo); + assert(ModifierLen == 0 && "No modifiers for strings yet"); + + // Don't crash if get passed a null pointer by accident. + if (!II) { + const char *S = "(null)"; + OutStr.append(S, S + strlen(S)); + continue; + } + + llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\''; + break; + } + case Diagnostic::ak_qualtype: + case Diagnostic::ak_declarationname: + case Diagnostic::ak_nameddecl: + case Diagnostic::ak_nestednamespec: + case Diagnostic::ak_declcontext: + getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo), + Modifier, ModifierLen, + Argument, ArgumentLen, + FormattedArgs.data(), FormattedArgs.size(), + OutStr); + break; + } + + // Remember this argument info for subsequent formatting operations. Turn + // std::strings into a null terminated string to make it be the same case as + // all the other ones. + if (Kind != Diagnostic::ak_std_string) + FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo))); + else + FormattedArgs.push_back(std::make_pair(Diagnostic::ak_c_string, + (intptr_t)getArgStdStr(ArgNo).c_str())); + + } +} + +StoredDiagnostic::StoredDiagnostic() { } + +StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, + llvm::StringRef Message) + : Level(Level), Loc(), Message(Message) { } + +StoredDiagnostic::StoredDiagnostic(Diagnostic::Level Level, + const DiagnosticInfo &Info) + : Level(Level), Loc(Info.getLocation()) +{ + llvm::SmallString<64> Message; + Info.FormatDiagnostic(Message); + this->Message.assign(Message.begin(), Message.end()); + + Ranges.reserve(Info.getNumRanges()); + for (unsigned I = 0, N = Info.getNumRanges(); I != N; ++I) + Ranges.push_back(Info.getRange(I)); + + FixIts.reserve(Info.getNumFixItHints()); + for (unsigned I = 0, N = Info.getNumFixItHints(); I != N; ++I) + FixIts.push_back(Info.getFixItHint(I)); +} + +StoredDiagnostic::~StoredDiagnostic() { } + +static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) { + OS.write((const char *)&Value, sizeof(unsigned)); +} + +static void WriteString(llvm::raw_ostream &OS, llvm::StringRef String) { + WriteUnsigned(OS, String.size()); + OS.write(String.data(), String.size()); +} + +static void WriteSourceLocation(llvm::raw_ostream &OS, + SourceManager *SM, + SourceLocation Location) { + if (!SM || Location.isInvalid()) { + // If we don't have a source manager or this location is invalid, + // just write an invalid location. + WriteUnsigned(OS, 0); + WriteUnsigned(OS, 0); + WriteUnsigned(OS, 0); + return; + } + + Location = SM->getInstantiationLoc(Location); + std::pair<FileID, unsigned> Decomposed = SM->getDecomposedLoc(Location); + + const FileEntry *FE = SM->getFileEntryForID(Decomposed.first); + if (FE) + WriteString(OS, FE->getName()); + else { + // Fallback to using the buffer name when there is no entry. + WriteString(OS, SM->getBuffer(Decomposed.first)->getBufferIdentifier()); + } + + WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second)); + WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second)); +} + +void StoredDiagnostic::Serialize(llvm::raw_ostream &OS) const { + SourceManager *SM = 0; + if (getLocation().isValid()) + SM = &const_cast<SourceManager &>(getLocation().getManager()); + + // Write a short header to help identify diagnostics. + OS << (char)0x06 << (char)0x07; + + // Write the diagnostic level and location. + WriteUnsigned(OS, (unsigned)Level); + WriteSourceLocation(OS, SM, getLocation()); + + // Write the diagnostic message. + llvm::SmallString<64> Message; + WriteString(OS, getMessage()); + + // Count the number of ranges that don't point into macros, since + // only simple file ranges serialize well. + unsigned NumNonMacroRanges = 0; + for (range_iterator R = range_begin(), REnd = range_end(); R != REnd; ++R) { + if (R->getBegin().isMacroID() || R->getEnd().isMacroID()) + continue; + + ++NumNonMacroRanges; + } + + // Write the ranges. + WriteUnsigned(OS, NumNonMacroRanges); + if (NumNonMacroRanges) { + for (range_iterator R = range_begin(), REnd = range_end(); R != REnd; ++R) { + if (R->getBegin().isMacroID() || R->getEnd().isMacroID()) + continue; + + WriteSourceLocation(OS, SM, R->getBegin()); + WriteSourceLocation(OS, SM, R->getEnd()); + } + } + + // Determine if all of the fix-its involve rewrites with simple file + // locations (not in macro instantiations). If so, we can write + // fix-it information. + unsigned NumFixIts = 0; + for (fixit_iterator F = fixit_begin(), FEnd = fixit_end(); F != FEnd; ++F) { + if (F->RemoveRange.isValid() && + (F->RemoveRange.getBegin().isMacroID() || + F->RemoveRange.getEnd().isMacroID())) { + NumFixIts = 0; + break; + } + + if (F->InsertionLoc.isValid() && F->InsertionLoc.isMacroID()) { + NumFixIts = 0; + break; + } + + ++NumFixIts; + } + + // Write the fix-its. + WriteUnsigned(OS, NumFixIts); + for (fixit_iterator F = fixit_begin(), FEnd = fixit_end(); F != FEnd; ++F) { + WriteSourceLocation(OS, SM, F->RemoveRange.getBegin()); + WriteSourceLocation(OS, SM, F->RemoveRange.getEnd()); + WriteSourceLocation(OS, SM, F->InsertionLoc); + WriteString(OS, F->CodeToInsert); + } +} + +static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, + unsigned &Value) { + if (Memory + sizeof(unsigned) > MemoryEnd) + return true; + + memmove(&Value, Memory, sizeof(unsigned)); + Memory += sizeof(unsigned); + return false; +} + +static bool ReadSourceLocation(FileManager &FM, SourceManager &SM, + const char *&Memory, const char *MemoryEnd, + SourceLocation &Location) { + // Read the filename. + unsigned FileNameLen = 0; + if (ReadUnsigned(Memory, MemoryEnd, FileNameLen) || + Memory + FileNameLen > MemoryEnd) + return true; + + llvm::StringRef FileName(Memory, FileNameLen); + Memory += FileNameLen; + + // Read the line, column. + unsigned Line = 0, Column = 0; + if (ReadUnsigned(Memory, MemoryEnd, Line) || + ReadUnsigned(Memory, MemoryEnd, Column)) + return true; + + if (FileName.empty()) { + Location = SourceLocation(); + return false; + } + + const FileEntry *File = FM.getFile(FileName); + if (!File) + return true; + + // Make sure that this file has an entry in the source manager. + if (!SM.hasFileInfo(File)) + SM.createFileID(File, SourceLocation(), SrcMgr::C_User); + + Location = SM.getLocation(File, Line, Column); + return false; +} + +StoredDiagnostic +StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM, + const char *&Memory, const char *MemoryEnd) { + while (true) { + if (Memory == MemoryEnd) + return StoredDiagnostic(); + + if (*Memory != 0x06) { + ++Memory; + continue; + } + + ++Memory; + if (Memory == MemoryEnd) + return StoredDiagnostic(); + + if (*Memory != 0x07) { + ++Memory; + continue; + } + + // We found the header. We're done. + ++Memory; + break; + } + + // Read the severity level. + unsigned Level = 0; + if (ReadUnsigned(Memory, MemoryEnd, Level) || Level > Diagnostic::Fatal) + return StoredDiagnostic(); + + // Read the source location. + SourceLocation Location; + if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Location)) + return StoredDiagnostic(); + + // Read the diagnostic text. + if (Memory == MemoryEnd) + return StoredDiagnostic(); + + unsigned MessageLen = 0; + if (ReadUnsigned(Memory, MemoryEnd, MessageLen) || + Memory + MessageLen > MemoryEnd) + return StoredDiagnostic(); + + llvm::StringRef Message(Memory, MessageLen); + Memory += MessageLen; + + + // At this point, we have enough information to form a diagnostic. Do so. + StoredDiagnostic Diag; + Diag.Level = (Diagnostic::Level)Level; + Diag.Loc = FullSourceLoc(Location, SM); + Diag.Message = Message; + if (Memory == MemoryEnd) + return Diag; + + // Read the source ranges. + unsigned NumSourceRanges = 0; + if (ReadUnsigned(Memory, MemoryEnd, NumSourceRanges)) + return Diag; + for (unsigned I = 0; I != NumSourceRanges; ++I) { + SourceLocation Begin, End; + if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Begin) || + ReadSourceLocation(FM, SM, Memory, MemoryEnd, End)) + return Diag; + + Diag.Ranges.push_back(SourceRange(Begin, End)); + } + + // Read the fix-it hints. + unsigned NumFixIts = 0; + if (ReadUnsigned(Memory, MemoryEnd, NumFixIts)) + return Diag; + for (unsigned I = 0; I != NumFixIts; ++I) { + SourceLocation RemoveBegin, RemoveEnd, InsertionLoc; + unsigned InsertLen = 0; + if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) || + ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) || + ReadSourceLocation(FM, SM, Memory, MemoryEnd, InsertionLoc) || + ReadUnsigned(Memory, MemoryEnd, InsertLen) || + Memory + InsertLen > MemoryEnd) { + Diag.FixIts.clear(); + return Diag; + } + + FixItHint Hint; + Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd); + Hint.InsertionLoc = InsertionLoc; + Hint.CodeToInsert.assign(Memory, Memory + InsertLen); + Memory += InsertLen; + Diag.FixIts.push_back(Hint); + } + + return Diag; +} + +/// IncludeInDiagnosticCounts - This method (whose default implementation +/// returns true) indicates whether the diagnostics handled by this +/// DiagnosticClient should be included in the number of diagnostics +/// reported by Diagnostic. +bool DiagnosticClient::IncludeInDiagnosticCounts() const { return true; } + +PartialDiagnostic::StorageAllocator::StorageAllocator() { + for (unsigned I = 0; I != NumCached; ++I) + FreeList[I] = Cached + I; + NumFreeListEntries = NumCached; +} + +PartialDiagnostic::StorageAllocator::~StorageAllocator() { + assert(NumFreeListEntries == NumCached && "A partial is on the lamb"); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp new file mode 100644 index 0000000..c4296c3 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp @@ -0,0 +1,398 @@ +///===--- 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/Support/raw_ostream.h" +#include "llvm/System/Path.h" +#include "llvm/Config/config.h" +#include <map> +#include <set> +#include <string> +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) + +//===----------------------------------------------------------------------===// +// Windows. +//===----------------------------------------------------------------------===// + +#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, llvm::BumpPtrAllocator> 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(); } +}; + +//===----------------------------------------------------------------------===// +// Unix-like Systems. +//===----------------------------------------------------------------------===// + +#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, + StatBuf.st_mode)).first); + } + + size_t size() { return UniqueFiles.size(); } +}; + +#endif + +//===----------------------------------------------------------------------===// +// Common logic. +//===----------------------------------------------------------------------===// + +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; + for (llvm::SmallVectorImpl<FileEntry *>::iterator + V = VirtualFileEntries.begin(), + VEnd = VirtualFileEntries.end(); + V != VEnd; + ++V) + delete *V; +} + +void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) { + assert(statCache && "No stat cache provided?"); + if (AtBeginning || StatCache.get() == 0) { + statCache->setNextStatCache(StatCache.take()); + StatCache.reset(statCache); + return; + } + + StatSysCallCache *LastCache = StatCache.get(); + while (LastCache->getNextStatCache()) + LastCache = LastCache->getNextStatCache(); + + LastCache->setNextStatCache(statCache); +} + +void FileManager::removeStatCache(StatSysCallCache *statCache) { + if (!statCache) + return; + + if (StatCache.get() == statCache) { + // This is the first stat cache. + StatCache.reset(StatCache->takeNextStatCache()); + return; + } + + // Find the stat cache in the list. + StatSysCallCache *PrevCache = StatCache.get(); + while (PrevCache && PrevCache->getNextStatCache() != statCache) + PrevCache = PrevCache->getNextStatCache(); + if (PrevCache) + PrevCache->setNextStatCache(statCache->getNextStatCache()); + else + assert(false && "Stat cache not found for removal"); +} + +/// \brief Retrieve the directory that the given file name resides in. +static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr, + const char *NameStart, + const char *NameEnd) { + // 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; + // Ignore duplicate //'s. + while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1])) + --SlashPos; + + if (SlashPos < NameStart) { + // Use the current directory if file has no path component. + const char *Name = "."; + return FileMgr.getDirectory(Name, Name+1); + } else if (SlashPos == NameEnd-1) + return 0; // If filename ends with a /, it's a directory. + else + return FileMgr.getDirectory(NameStart, SlashPos); +} + +/// 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) { + // stat doesn't like trailing separators (at least on Windows). + if (((NameEnd - NameStart) > 1) && + ((*(NameEnd - 1) == '/') || (*(NameEnd - 1) == '\\'))) + 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_cached(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); + + + // Get the null-terminated file name as stored as the key of the + // FileEntries map. + const char *InterndFileName = NamedFileEnt.getKeyData(); + + const DirectoryEntry *DirInfo + = getDirectoryFromFile(*this, NameStart, NameEnd); + if (DirInfo == 0) // Directory doesn't exist, file can't exist. + return 0; + + // 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::errs() << "STATING: " << Filename; + if (stat_cached(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::errs() << ": Not existing\n"; + return 0; + } + //llvm::errs() << ": 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; +} + +const FileEntry * +FileManager::getVirtualFile(const llvm::StringRef &Filename, + off_t Size, time_t ModificationTime) { + const char *NameStart = Filename.begin(), *NameEnd = Filename.end(); + + ++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); + + const DirectoryEntry *DirInfo + = getDirectoryFromFile(*this, NameStart, NameEnd); + if (DirInfo == 0) // Directory doesn't exist, file can't exist. + return 0; + + FileEntry *UFE = new FileEntry(); + VirtualFileEntries.push_back(UFE); + NamedFileEnt.setValue(UFE); + + UFE->Name = NamedFileEnt.getKeyData(); + UFE->Size = Size; + UFE->ModTime = ModificationTime; + UFE->Dir = DirInfo; + UFE->UID = NextFileUID++; + return UFE; +} + +void FileManager::PrintStats() const { + llvm::errs() << "\n*** File Manager Stats:\n"; + llvm::errs() << UniqueFiles.size() << " files found, " + << UniqueDirs.size() << " dirs found.\n"; + llvm::errs() << NumDirLookups << " dir lookups, " + << NumDirCacheMisses << " dir cache misses.\n"; + llvm::errs() << NumFileLookups << " file lookups, " + << NumFileCacheMisses << " file cache misses.\n"; + + //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; +} + +int MemorizeStatCalls::stat(const char *path, struct stat *buf) { + int result = StatSysCallCache::stat(path, buf); + + // Do not cache failed stats, it is easy to construct common inconsistent + // situations if we do, and they are not important for PCH performance (which + // currently only needs the stats to construct the initial FileManager + // entries). + if (result != 0) + return result; + + // Cache file 'stat' results and directories with absolutely paths. + if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) + StatCalls[path] = StatResult(result, *buf); + + return result; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp new file mode 100644 index 0000000..8993e67 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp @@ -0,0 +1,402 @@ +//===--- 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/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdio> + +using namespace clang; + +//===----------------------------------------------------------------------===// +// IdentifierInfo Implementation +//===----------------------------------------------------------------------===// + +IdentifierInfo::IdentifierInfo() { + TokenID = tok::identifier; + ObjCOrBuiltinID = 0; + HasMacro = false; + IsExtension = false; + IsPoisoned = false; + IsCPPOperatorKeyword = false; + NeedsHandleIdentifier = false; + FETokenInfo = 0; + Entry = 0; +} + +//===----------------------------------------------------------------------===// +// IdentifierTable Implementation +//===----------------------------------------------------------------------===// + +IdentifierInfoLookup::~IdentifierInfoLookup() {} + +ExternalIdentifierLookup::~ExternalIdentifierLookup() {} + +IdentifierTable::IdentifierTable(const LangOptions &LangOpts, + IdentifierInfoLookup* externalLookup) + : HashTable(8192), // Start with space for 8K identifiers. + ExternalLookup(externalLookup) { + + // Populate the identifier table with info about keywords for the current + // language. + AddKeywords(LangOpts); +} + +//===----------------------------------------------------------------------===// +// Language Keyword Implementation +//===----------------------------------------------------------------------===// + +// Constants for TokenKinds.def +namespace { + enum { + KEYALL = 1, + KEYC99 = 2, + KEYCXX = 4, + KEYCXX0X = 8, + KEYGNU = 16, + KEYMS = 32, + BOOLSUPPORT = 64, + KEYALTIVEC = 128, + KEYNOMS = 256 + }; +} + +/// 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 2 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 0 if disabled in the +/// specified language. +static void AddKeyword(llvm::StringRef Keyword, + tok::TokenKind TokenCode, unsigned Flags, + const LangOptions &LangOpts, IdentifierTable &Table) { + unsigned AddResult = 0; + if (Flags & KEYALL) AddResult = 2; + else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2; + else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2; + else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2; + else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1; + else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1; + else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2; + else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2; + else if (!LangOpts.Microsoft && (Flags & KEYNOMS)) AddResult = 2; + + // Don't add this keyword if disabled in this language. + if (AddResult == 0) return; + + IdentifierInfo &Info = Table.get(Keyword); + Info.setTokenID(TokenCode); + Info.setIsExtensionToken(AddResult == 1); +} + +/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative +/// representations. +static void AddCXXOperatorKeyword(llvm::StringRef Keyword, + tok::TokenKind TokenCode, + IdentifierTable &Table) { + IdentifierInfo &Info = Table.get(Keyword); + Info.setTokenID(TokenCode); + Info.setIsCPlusPlusOperatorKeyword(); +} + +/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or +/// "property". +static void AddObjCKeyword(llvm::StringRef Name, + tok::ObjCKeywordKind ObjCID, + IdentifierTable &Table) { + Table.get(Name).setObjCKeywordID(ObjCID); +} + +/// AddKeywords - Add all keywords to the symbol table. +/// +void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { + // Add keywords and tokens for the current language. +#define KEYWORD(NAME, FLAGS) \ + AddKeyword(llvm::StringRef(#NAME), tok::kw_ ## NAME, \ + FLAGS, LangOpts, *this); +#define ALIAS(NAME, TOK, FLAGS) \ + AddKeyword(llvm::StringRef(NAME), tok::kw_ ## TOK, \ + FLAGS, LangOpts, *this); +#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \ + if (LangOpts.CXXOperatorNames) \ + AddCXXOperatorKeyword(llvm::StringRef(#NAME), tok::ALIAS, *this); +#define OBJC1_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC1) \ + AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this); +#define OBJC2_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC2) \ + AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##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 = getNameStart(); + 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); + + CASE(16, '_', 'i', __include_macros); +#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()); +} + +namespace clang { +/// 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. +class MultiKeywordSelector + : public DeclarationNameExtra, public llvm::FoldingSetNode { + MultiKeywordSelector(unsigned nKeys) { + ExtraKindOrNumArgs = NUM_EXTRA_KINDS + nKeys; + } +public: + // Constructor for keyword selectors. + MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) { + assert((nKeys > 1) && "not a multi-keyword selector"); + ExtraKindOrNumArgs = NUM_EXTRA_KINDS + 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 ExtraKindOrNumArgs - NUM_EXTRA_KINDS; } + + 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()+getNumArgs(); + } + IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { + assert(i < getNumArgs() && "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(), getNumArgs()); + } +}; +} // 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 (getIdentifierInfoFlag()) { + assert(argIndex == 0 && "illegal keyword index"); + return getAsIdentifierInfo(); + } + // 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 { + llvm::SmallString<256> Str; + llvm::raw_svector_ostream OS(Str); + for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { + if (*I) + OS << (*I)->getName(); + OS << ':'; + } + + return OS.str(); +} + +std::string Selector::getAsString() const { + if (InfoPtr == 0) + return "<null selector>"; + + if (InfoPtr & ArgFlags) { + IdentifierInfo *II = getAsIdentifierInfo(); + + // If the number of arguments is 0 then II is guaranteed to not be null. + if (getNumArgs() == 0) + return II->getName(); + + if (!II) + return ":"; + + return II->getName().str() + ":"; + } + + // We have a multiple keyword selector (no embedded flags). + return reinterpret_cast<MultiKeywordSelector *>(InfoPtr)->getName(); +} + + +namespace { + struct SelectorTableImpl { + llvm::FoldingSet<MultiKeywordSelector> Table; + llvm::BumpPtrAllocator Allocator; + }; +} // end anonymous namespace. + +static SelectorTableImpl &getSelectorTableImpl(void *P) { + return *static_cast<SelectorTableImpl*>(P); +} + + +Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { + if (nKeys < 2) + return Selector(IIV[0], nKeys); + + SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl); + + // Unique selector, to guarantee there is one per name. + llvm::FoldingSetNodeID ID; + MultiKeywordSelector::Profile(ID, IIV, nKeys); + + void *InsertPos = 0; + if (MultiKeywordSelector *SI = + SelTabImpl.Table.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. + unsigned Size = sizeof(MultiKeywordSelector) + nKeys*sizeof(IdentifierInfo *); + MultiKeywordSelector *SI = + (MultiKeywordSelector*)SelTabImpl.Allocator.Allocate(Size, + llvm::alignof<MultiKeywordSelector>()); + new (SI) MultiKeywordSelector(nKeys, IIV); + SelTabImpl.Table.InsertNode(SI, InsertPos); + return Selector(SI); +} + +SelectorTable::SelectorTable() { + Impl = new SelectorTableImpl(); +} + +SelectorTable::~SelectorTable() { + delete &getSelectorTableImpl(Impl); +} + +const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) { + switch (Operator) { + case OO_None: + case NUM_OVERLOADED_OPERATORS: + return 0; + +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + case OO_##Name: return Spelling; +#include "clang/Basic/OperatorKinds.def" + } + + return 0; +} + diff --git a/contrib/llvm/tools/clang/lib/Basic/Makefile b/contrib/llvm/tools/clang/lib/Basic/Makefile new file mode 100644 index 0000000..58ac7eb --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Makefile @@ -0,0 +1,35 @@ +##===- 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 + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +ifdef CLANG_VENDOR +CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "' +endif + +include $(LEVEL)/Makefile.common + +SVN_REVISION := $(shell $(LLVM_SRC_ROOT)/utils/GetSourceVersion $(PROJ_SRC_DIR)/../..) + +CPP.Defines += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include \ + -DSVN_REVISION='"$(SVN_REVISION)"' + +$(ObjDir)/.ver-svn .ver: $(ObjDir)/.dir + @if [ '$(SVN_REVISION)' != '$(shell cat $(ObjDir)/.ver-svn 2>/dev/null)' ]; then\ + echo '$(SVN_REVISION)' > $(ObjDir)/.ver-svn; \ + fi +$(ObjDir)/.ver-svn: .ver +$(ObjDir)/Version.o: $(ObjDir)/.ver-svn diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp new file mode 100644 index 0000000..7412b95 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp @@ -0,0 +1,124 @@ +//==--- 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 accessor methods for the FullSourceLoc class. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdio> +using namespace clang; + +//===----------------------------------------------------------------------===// +// PrettyStackTraceLoc +//===----------------------------------------------------------------------===// + +void PrettyStackTraceLoc::print(llvm::raw_ostream &OS) const { + if (Loc.isValid()) { + Loc.print(OS, SM); + OS << ": "; + } + OS << Message << '\n'; +} + +//===----------------------------------------------------------------------===// +// SourceLocation +//===----------------------------------------------------------------------===// + +void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{ + if (!isValid()) { + OS << "<invalid loc>"; + return; + } + + if (isFileID()) { + PresumedLoc PLoc = SM.getPresumedLoc(*this); + // The instantiation and spelling pos is identical for file locs. + OS << PLoc.getFilename() << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); + return; + } + + SM.getInstantiationLoc(*this).print(OS, SM); + + OS << " <Spelling="; + SM.getSpellingLoc(*this).print(OS, SM); + OS << '>'; +} + +void SourceLocation::dump(const SourceManager &SM) const { + print(llvm::errs(), SM); +} + +//===----------------------------------------------------------------------===// +// FullSourceLoc +//===----------------------------------------------------------------------===// + +FileID FullSourceLoc::getFileID() const { + assert(isValid()); + return SrcMgr->getFileID(*this); +} + + +FullSourceLoc FullSourceLoc::getInstantiationLoc() const { + assert(isValid()); + return FullSourceLoc(SrcMgr->getInstantiationLoc(*this), *SrcMgr); +} + +FullSourceLoc FullSourceLoc::getSpellingLoc() const { + assert(isValid()); + return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr); +} + +unsigned FullSourceLoc::getInstantiationLineNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getInstantiationLineNumber(*this, Invalid); +} + +unsigned FullSourceLoc::getInstantiationColumnNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getInstantiationColumnNumber(*this, Invalid); +} + +unsigned FullSourceLoc::getSpellingLineNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getSpellingLineNumber(*this, Invalid); +} + +unsigned FullSourceLoc::getSpellingColumnNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getSpellingColumnNumber(*this, Invalid); +} + +bool FullSourceLoc::isInSystemHeader() const { + assert(isValid()); + return SrcMgr->isInSystemHeader(*this); +} + +const char *FullSourceLoc::getCharacterData(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getCharacterData(*this, Invalid); +} + +const llvm::MemoryBuffer* FullSourceLoc::getBuffer(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getBuffer(SrcMgr->getFileID(*this), Invalid); +} + +llvm::StringRef FullSourceLoc::getBufferData(bool *Invalid) const { + return getBuffer(Invalid)->getBuffer(); +} + +std::pair<FileID, unsigned> FullSourceLoc::getDecomposedLoc() const { + return SrcMgr->getDecomposedLoc(*this); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp new file mode 100644 index 0000000..e6d9785 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp @@ -0,0 +1,1288 @@ +//===--- 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/SourceManagerInternals.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" +#include <algorithm> +#include <string> +#include <cstring> + +using namespace clang; +using namespace SrcMgr; +using llvm::MemoryBuffer; + +//===----------------------------------------------------------------------===// +// SourceManager Helper Classes +//===----------------------------------------------------------------------===// + +ContentCache::~ContentCache() { + delete Buffer.getPointer(); +} + +/// getSizeBytesMapped - Returns the number of bytes actually mapped for +/// this ContentCache. This can be 0 if the MemBuffer was not actually +/// instantiated. +unsigned ContentCache::getSizeBytesMapped() const { + return Buffer.getPointer() ? Buffer.getPointer()->getBufferSize() : 0; +} + +/// getSize - Returns the size of the content encapsulated by this ContentCache. +/// This can be the size of the source file or the size of an arbitrary +/// scratch buffer. If the ContentCache encapsulates a source file, that +/// file is not lazily brought in from disk to satisfy this query. +unsigned ContentCache::getSize() const { + return Buffer.getPointer() ? (unsigned) Buffer.getPointer()->getBufferSize() + : (unsigned) Entry->getSize(); +} + +void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { + assert(B != Buffer.getPointer()); + + delete Buffer.getPointer(); + Buffer.setPointer(B); + Buffer.setInt(false); +} + +const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, + const SourceManager &SM, + SourceLocation Loc, + bool *Invalid) const { + if (Invalid) + *Invalid = false; + + // Lazily create the Buffer for ContentCaches that wrap files. + if (!Buffer.getPointer() && Entry) { + std::string ErrorStr; + struct stat FileInfo; + Buffer.setPointer(MemoryBuffer::getFile(Entry->getName(), &ErrorStr, + Entry->getSize(), &FileInfo)); + Buffer.setInt(false); + + // If we were unable to open the file, then we are in an inconsistent + // situation where the content cache referenced a file which no longer + // exists. Most likely, we were using a stat cache with an invalid entry but + // the file could also have been removed during processing. Since we can't + // really deal with this situation, just create an empty buffer. + // + // FIXME: This is definitely not ideal, but our immediate clients can't + // currently handle returning a null entry here. Ideally we should detect + // that we are in an inconsistent situation and error out as quickly as + // possible. + if (!Buffer.getPointer()) { + const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n"); + Buffer.setPointer(MemoryBuffer::getNewMemBuffer(Entry->getSize(), + "<invalid>")); + char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart()); + for (unsigned i = 0, e = Entry->getSize(); i != e; ++i) + Ptr[i] = FillStr[i % FillStr.size()]; + + if (Diag.isDiagnosticInFlight()) + Diag.SetDelayedDiagnostic(diag::err_cannot_open_file, + Entry->getName(), ErrorStr); + else + Diag.Report(FullSourceLoc(Loc, SM), diag::err_cannot_open_file) + << Entry->getName() << ErrorStr; + + Buffer.setInt(true); + + // FIXME: This conditionalization is horrible, but we see spurious failures + // in the test suite due to this warning and no one has had time to hunt it + // down. So for now, we just don't emit this diagnostic on Win32, and hope + // nothing bad happens. + // + // PR6812. +#if !defined(LLVM_ON_WIN32) + } else if (FileInfo.st_size != Entry->getSize() || + FileInfo.st_mtime != Entry->getModificationTime()) { + // Check that the file's size and modification time are the same + // as in the file entry (which may have come from a stat cache). + if (Diag.isDiagnosticInFlight()) + Diag.SetDelayedDiagnostic(diag::err_file_modified, + Entry->getName()); + else + Diag.Report(FullSourceLoc(Loc, SM), diag::err_file_modified) + << Entry->getName(); + + Buffer.setInt(true); +#endif + } + + // If the buffer is valid, check to see if it has a UTF Byte Order Mark + // (BOM). We only support UTF-8 without a BOM right now. See + // http://en.wikipedia.org/wiki/Byte_order_mark for more information. + if (!Buffer.getInt()) { + llvm::StringRef BufStr = Buffer.getPointer()->getBuffer(); + const char *BOM = 0; + if (BufStr.startswith("\xFE\xBB\xBF")) + BOM = "UTF-8"; + else if (BufStr.startswith("\xFE\xFF")) + BOM = "UTF-16 (BE)"; + else if (BufStr.startswith("\xFF\xFE")) + BOM = "UTF-16 (LE)"; + else if (BufStr.startswith(llvm::StringRef("\x00\x00\xFE\xFF", 4))) + BOM = "UTF-32 (BE)"; + else if (BufStr.startswith(llvm::StringRef("\xFF\xFE\x00\x00", 4))) + BOM = "UTF-32 (LE)"; + else if (BufStr.startswith("\x2B\x2F\x76")) + BOM = "UTF-7"; + else if (BufStr.startswith("\xF7\x64\x4C")) + BOM = "UTF-1"; + else if (BufStr.startswith("\xDD\x73\x66\x73")) + BOM = "UTF-EBCDIC"; + else if (BufStr.startswith("\x0E\xFE\xFF")) + BOM = "SDSU"; + else if (BufStr.startswith("\xFB\xEE\x28")) + BOM = "BOCU-1"; + else if (BufStr.startswith("\x84\x31\x95\x33")) + BOM = "BOCU-1"; + + if (BOM) { + Diag.Report(FullSourceLoc(Loc, SM), diag::err_unsupported_bom) + << BOM << Entry->getName(); + Buffer.setInt(1); + } + } + } + + if (Invalid) + *Invalid = Buffer.getInt(); + + return Buffer.getPointer(); +} + +unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) { + // Look up the filename in the string table, returning the pre-existing value + // if it exists. + llvm::StringMapEntry<unsigned> &Entry = + FilenameIDs.GetOrCreateValue(Ptr, Ptr+Len, ~0U); + if (Entry.getValue() != ~0U) + return Entry.getValue(); + + // Otherwise, assign this the next available ID. + Entry.setValue(FilenamesByID.size()); + FilenamesByID.push_back(&Entry); + return FilenamesByID.size()-1; +} + +/// AddLineNote - Add a line note to the line table that indicates that there +/// is a #line at the specified FID/Offset location which changes the presumed +/// location to LineNo/FilenameID. +void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset, + unsigned LineNo, int FilenameID) { + std::vector<LineEntry> &Entries = LineEntries[FID]; + + assert((Entries.empty() || Entries.back().FileOffset < Offset) && + "Adding line entries out of order!"); + + SrcMgr::CharacteristicKind Kind = SrcMgr::C_User; + unsigned IncludeOffset = 0; + + if (!Entries.empty()) { + // If this is a '#line 4' after '#line 42 "foo.h"', make sure to remember + // that we are still in "foo.h". + if (FilenameID == -1) + FilenameID = Entries.back().FilenameID; + + // If we are after a line marker that switched us to system header mode, or + // that set #include information, preserve it. + Kind = Entries.back().FileKind; + IncludeOffset = Entries.back().IncludeOffset; + } + + Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, Kind, + IncludeOffset)); +} + +/// AddLineNote This is the same as the previous version of AddLineNote, but is +/// used for GNU line markers. If EntryExit is 0, then this doesn't change the +/// presumed #include stack. If it is 1, this is a file entry, if it is 2 then +/// this is a file exit. FileKind specifies whether this is a system header or +/// extern C system header. +void LineTableInfo::AddLineNote(unsigned FID, unsigned Offset, + unsigned LineNo, int FilenameID, + unsigned EntryExit, + SrcMgr::CharacteristicKind FileKind) { + assert(FilenameID != -1 && "Unspecified filename should use other accessor"); + + std::vector<LineEntry> &Entries = LineEntries[FID]; + + assert((Entries.empty() || Entries.back().FileOffset < Offset) && + "Adding line entries out of order!"); + + unsigned IncludeOffset = 0; + if (EntryExit == 0) { // No #include stack change. + IncludeOffset = Entries.empty() ? 0 : Entries.back().IncludeOffset; + } else if (EntryExit == 1) { + IncludeOffset = Offset-1; + } else if (EntryExit == 2) { + assert(!Entries.empty() && Entries.back().IncludeOffset && + "PPDirectives should have caught case when popping empty include stack"); + + // Get the include loc of the last entries' include loc as our include loc. + IncludeOffset = 0; + if (const LineEntry *PrevEntry = + FindNearestLineEntry(FID, Entries.back().IncludeOffset)) + IncludeOffset = PrevEntry->IncludeOffset; + } + + Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, FileKind, + IncludeOffset)); +} + + +/// FindNearestLineEntry - Find the line entry nearest to FID that is before +/// it. If there is no line entry before Offset in FID, return null. +const LineEntry *LineTableInfo::FindNearestLineEntry(unsigned FID, + unsigned Offset) { + const std::vector<LineEntry> &Entries = LineEntries[FID]; + assert(!Entries.empty() && "No #line entries for this FID after all!"); + + // It is very common for the query to be after the last #line, check this + // first. + if (Entries.back().FileOffset <= Offset) + return &Entries.back(); + + // Do a binary search to find the maximal element that is still before Offset. + std::vector<LineEntry>::const_iterator I = + std::upper_bound(Entries.begin(), Entries.end(), Offset); + if (I == Entries.begin()) return 0; + return &*--I; +} + +/// \brief Add a new line entry that has already been encoded into +/// the internal representation of the line table. +void LineTableInfo::AddEntry(unsigned FID, + const std::vector<LineEntry> &Entries) { + LineEntries[FID] = Entries; +} + +/// getLineTableFilenameID - Return the uniqued ID for the specified filename. +/// +unsigned SourceManager::getLineTableFilenameID(const char *Ptr, unsigned Len) { + if (LineTable == 0) + LineTable = new LineTableInfo(); + return LineTable->getLineTableFilenameID(Ptr, Len); +} + + +/// AddLineNote - Add a line note to the line table for the FileID and offset +/// specified by Loc. If FilenameID is -1, it is considered to be +/// unspecified. +void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, + int FilenameID) { + std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + + const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile(); + + // Remember that this file has #line directives now if it doesn't already. + const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives(); + + if (LineTable == 0) + LineTable = new LineTableInfo(); + LineTable->AddLineNote(LocInfo.first.ID, LocInfo.second, LineNo, FilenameID); +} + +/// AddLineNote - Add a GNU line marker to the line table. +void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, + int FilenameID, bool IsFileEntry, + bool IsFileExit, bool IsSystemHeader, + bool IsExternCHeader) { + // If there is no filename and no flags, this is treated just like a #line, + // which does not change the flags of the previous line marker. + if (FilenameID == -1) { + assert(!IsFileEntry && !IsFileExit && !IsSystemHeader && !IsExternCHeader && + "Can't set flags without setting the filename!"); + return AddLineNote(Loc, LineNo, FilenameID); + } + + std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile(); + + // Remember that this file has #line directives now if it doesn't already. + const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives(); + + if (LineTable == 0) + LineTable = new LineTableInfo(); + + SrcMgr::CharacteristicKind FileKind; + if (IsExternCHeader) + FileKind = SrcMgr::C_ExternCSystem; + else if (IsSystemHeader) + FileKind = SrcMgr::C_System; + else + FileKind = SrcMgr::C_User; + + unsigned EntryExit = 0; + if (IsFileEntry) + EntryExit = 1; + else if (IsFileExit) + EntryExit = 2; + + LineTable->AddLineNote(LocInfo.first.ID, LocInfo.second, LineNo, FilenameID, + EntryExit, FileKind); +} + +LineTableInfo &SourceManager::getLineTable() { + if (LineTable == 0) + LineTable = new LineTableInfo(); + return *LineTable; +} + +//===----------------------------------------------------------------------===// +// Private 'Create' methods. +//===----------------------------------------------------------------------===// + +SourceManager::~SourceManager() { + delete LineTable; + + // Delete FileEntry objects corresponding to content caches. Since the actual + // content cache objects are bump pointer allocated, we just have to run the + // dtors, but we call the deallocate method for completeness. + for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) { + MemBufferInfos[i]->~ContentCache(); + ContentCacheAlloc.Deallocate(MemBufferInfos[i]); + } + for (llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator + I = FileInfos.begin(), E = FileInfos.end(); I != E; ++I) { + I->second->~ContentCache(); + ContentCacheAlloc.Deallocate(I->second); + } +} + +void SourceManager::clearIDTables() { + MainFileID = FileID(); + SLocEntryTable.clear(); + LastLineNoFileIDQuery = FileID(); + LastLineNoContentCache = 0; + LastFileIDLookup = FileID(); + + if (LineTable) + LineTable->clear(); + + // Use up FileID #0 as an invalid instantiation. + NextOffset = 0; + createInstantiationLoc(SourceLocation(),SourceLocation(),SourceLocation(), 1); +} + +/// getOrCreateContentCache - Create or return a cached ContentCache for the +/// specified file. +const ContentCache * +SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) { + assert(FileEnt && "Didn't specify a file entry to use?"); + + // Do we already have information about this file? + ContentCache *&Entry = FileInfos[FileEnt]; + if (Entry) return Entry; + + // Nope, create a new Cache entry. Make sure it is at least 8-byte aligned + // so that FileInfo can use the low 3 bits of the pointer for its own + // nefarious purposes. + unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment; + EntryAlign = std::max(8U, EntryAlign); + Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign); + new (Entry) ContentCache(FileEnt); + 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. Make sure + // it is at least 8-byte aligned so that FileInfo can use the low 3 bits of + // the pointer for its own nefarious purposes. + unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment; + EntryAlign = std::max(8U, EntryAlign); + ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign); + new (Entry) ContentCache(); + MemBufferInfos.push_back(Entry); + Entry->setBuffer(Buffer); + return Entry; +} + +void SourceManager::PreallocateSLocEntries(ExternalSLocEntrySource *Source, + unsigned NumSLocEntries, + unsigned NextOffset) { + ExternalSLocEntries = Source; + this->NextOffset = NextOffset; + SLocEntryLoaded.resize(NumSLocEntries + 1); + SLocEntryLoaded[0] = true; + SLocEntryTable.resize(SLocEntryTable.size() + NumSLocEntries); +} + +void SourceManager::ClearPreallocatedSLocEntries() { + unsigned I = 0; + for (unsigned N = SLocEntryLoaded.size(); I != N; ++I) + if (!SLocEntryLoaded[I]) + break; + + // We've already loaded all preallocated source location entries. + if (I == SLocEntryLoaded.size()) + return; + + // Remove everything from location I onward. + SLocEntryTable.resize(I); + SLocEntryLoaded.clear(); + ExternalSLocEntries = 0; +} + + +//===----------------------------------------------------------------------===// +// Methods to create new FileID's and instantiations. +//===----------------------------------------------------------------------===// + +/// 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. +FileID SourceManager::createFileID(const ContentCache *File, + SourceLocation IncludePos, + SrcMgr::CharacteristicKind FileCharacter, + unsigned PreallocatedID, + unsigned Offset) { + if (PreallocatedID) { + // If we're filling in a preallocated ID, just load in the file + // entry and return. + assert(PreallocatedID < SLocEntryLoaded.size() && + "Preallocate ID out-of-range"); + assert(!SLocEntryLoaded[PreallocatedID] && + "Source location entry already loaded"); + assert(Offset && "Preallocate source location cannot have zero offset"); + SLocEntryTable[PreallocatedID] + = SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter)); + SLocEntryLoaded[PreallocatedID] = true; + FileID FID = FileID::get(PreallocatedID); + return FID; + } + + SLocEntryTable.push_back(SLocEntry::get(NextOffset, + FileInfo::get(IncludePos, File, + FileCharacter))); + unsigned FileSize = File->getSize(); + assert(NextOffset+FileSize+1 > NextOffset && "Ran out of source locations!"); + NextOffset += FileSize+1; + + // Set LastFileIDLookup to the newly created file. The next getFileID call is + // almost guaranteed to be from that file. + FileID FID = FileID::get(SLocEntryTable.size()-1); + return LastFileIDLookup = FID; +} + +/// createInstantiationLoc - Return a new SourceLocation that encodes the fact +/// that a token from SpellingLoc should actually be referenced from +/// InstantiationLoc. +SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc, + SourceLocation ILocStart, + SourceLocation ILocEnd, + unsigned TokLength, + unsigned PreallocatedID, + unsigned Offset) { + InstantiationInfo II = InstantiationInfo::get(ILocStart,ILocEnd, SpellingLoc); + if (PreallocatedID) { + // If we're filling in a preallocated ID, just load in the + // instantiation entry and return. + assert(PreallocatedID < SLocEntryLoaded.size() && + "Preallocate ID out-of-range"); + assert(!SLocEntryLoaded[PreallocatedID] && + "Source location entry already loaded"); + assert(Offset && "Preallocate source location cannot have zero offset"); + SLocEntryTable[PreallocatedID] = SLocEntry::get(Offset, II); + SLocEntryLoaded[PreallocatedID] = true; + return SourceLocation::getMacroLoc(Offset); + } + SLocEntryTable.push_back(SLocEntry::get(NextOffset, II)); + assert(NextOffset+TokLength+1 > NextOffset && "Ran out of source locations!"); + NextOffset += TokLength+1; + return SourceLocation::getMacroLoc(NextOffset-(TokLength+1)); +} + +const llvm::MemoryBuffer * +SourceManager::getMemoryBufferForFile(const FileEntry *File, + bool *Invalid) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); + assert(IR && "getOrCreateContentCache() cannot return NULL"); + return IR->getBuffer(Diag, *this, SourceLocation(), Invalid); +} + +bool SourceManager::overrideFileContents(const FileEntry *SourceFile, + const llvm::MemoryBuffer *Buffer) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile); + if (IR == 0) + return true; + + const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer); + return false; +} + +llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { + bool MyInvalid = false; + const llvm::MemoryBuffer *Buf = getBuffer(FID, &MyInvalid); + if (Invalid) + *Invalid = MyInvalid; + + if (MyInvalid) + return ""; + + return Buf->getBuffer(); +} + +//===----------------------------------------------------------------------===// +// SourceLocation manipulation methods. +//===----------------------------------------------------------------------===// + +/// getFileIDSlow - Return the FileID for a SourceLocation. This is a very hot +/// method that is used for all SourceManager queries that start with a +/// SourceLocation object. It is responsible for finding the entry in +/// SLocEntryTable which contains the specified location. +/// +FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { + assert(SLocOffset && "Invalid FileID"); + + // After the first and second level caches, I see two common sorts of + // behavior: 1) a lot of searched FileID's are "near" the cached file location + // or are "near" the cached instantiation location. 2) others are just + // completely random and may be a very long way away. + // + // To handle this, we do a linear search for up to 8 steps to catch #1 quickly + // then we fall back to a less cache efficient, but more scalable, binary + // search to find the location. + + // See if this is near the file point - worst case we start scanning from the + // most newly created FileID. + std::vector<SrcMgr::SLocEntry>::const_iterator I; + + if (SLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) { + // Neither loc prunes our search. + I = SLocEntryTable.end(); + } else { + // Perhaps it is near the file point. + I = SLocEntryTable.begin()+LastFileIDLookup.ID; + } + + // Find the FileID that contains this. "I" is an iterator that points to a + // FileID whose offset is known to be larger than SLocOffset. + unsigned NumProbes = 0; + while (1) { + --I; + if (ExternalSLocEntries) + getSLocEntry(FileID::get(I - SLocEntryTable.begin())); + if (I->getOffset() <= SLocOffset) { +#if 0 + printf("lin %d -> %d [%s] %d %d\n", SLocOffset, + I-SLocEntryTable.begin(), + I->isInstantiation() ? "inst" : "file", + LastFileIDLookup.ID, int(SLocEntryTable.end()-I)); +#endif + FileID Res = FileID::get(I-SLocEntryTable.begin()); + + // If this isn't an instantiation, remember it. We have good locality + // across FileID lookups. + if (!I->isInstantiation()) + LastFileIDLookup = Res; + NumLinearScans += NumProbes+1; + return Res; + } + if (++NumProbes == 8) + break; + } + + // Convert "I" back into an index. We know that it is an entry whose index is + // larger than the offset we are looking for. + unsigned GreaterIndex = I-SLocEntryTable.begin(); + // LessIndex - This is the lower bound of the range that we're searching. + // We know that the offset corresponding to the FileID is is less than + // SLocOffset. + unsigned LessIndex = 0; + NumProbes = 0; + while (1) { + unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex; + unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex)).getOffset(); + + ++NumProbes; + + // If the offset of the midpoint is too large, chop the high side of the + // range to the midpoint. + if (MidOffset > SLocOffset) { + GreaterIndex = MiddleIndex; + continue; + } + + // If the middle index contains the value, succeed and return. + if (isOffsetInFileID(FileID::get(MiddleIndex), SLocOffset)) { +#if 0 + printf("bin %d -> %d [%s] %d %d\n", SLocOffset, + I-SLocEntryTable.begin(), + I->isInstantiation() ? "inst" : "file", + LastFileIDLookup.ID, int(SLocEntryTable.end()-I)); +#endif + FileID Res = FileID::get(MiddleIndex); + + // If this isn't an instantiation, remember it. We have good locality + // across FileID lookups. + if (!I->isInstantiation()) + LastFileIDLookup = Res; + NumBinaryProbes += NumProbes; + return Res; + } + + // Otherwise, move the low-side up to the middle index. + LessIndex = MiddleIndex; + } +} + +SourceLocation SourceManager:: +getInstantiationLocSlowCase(SourceLocation Loc) const { + do { + // Note: If Loc indicates an offset into a token that came from a macro + // expansion (e.g. the 5th character of the token) we do not want to add + // this offset when going to the instantiation location. The instatiation + // location is the macro invocation, which the offset has nothing to do + // with. This is unlike when we get the spelling loc, because the offset + // directly correspond to the token whose spelling we're inspecting. + Loc = getSLocEntry(getFileID(Loc)).getInstantiation() + .getInstantiationLocStart(); + } while (!Loc.isFileID()); + + return Loc; +} + +SourceLocation SourceManager::getSpellingLocSlowCase(SourceLocation Loc) const { + do { + std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc); + Loc = getSLocEntry(LocInfo.first).getInstantiation().getSpellingLoc(); + Loc = Loc.getFileLocWithOffset(LocInfo.second); + } while (!Loc.isFileID()); + return Loc; +} + + +std::pair<FileID, unsigned> +SourceManager::getDecomposedInstantiationLocSlowCase(const SrcMgr::SLocEntry *E, + unsigned Offset) const { + // If this is an instantiation record, walk through all the instantiation + // points. + FileID FID; + SourceLocation Loc; + do { + Loc = E->getInstantiation().getInstantiationLocStart(); + + FID = getFileID(Loc); + E = &getSLocEntry(FID); + Offset += Loc.getOffset()-E->getOffset(); + } while (!Loc.isFileID()); + + return std::make_pair(FID, Offset); +} + +std::pair<FileID, unsigned> +SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, + unsigned Offset) const { + // If this is an instantiation record, walk through all the instantiation + // points. + FileID FID; + SourceLocation Loc; + do { + Loc = E->getInstantiation().getSpellingLoc(); + + FID = getFileID(Loc); + E = &getSLocEntry(FID); + Offset += Loc.getOffset()-E->getOffset(); + } while (!Loc.isFileID()); + + return std::make_pair(FID, Offset); +} + +/// getImmediateSpellingLoc - Given a SourceLocation object, return the +/// spelling location referenced by the ID. This is the first level down +/// towards the place where the characters that make up the lexed token can be +/// found. This should not generally be used by clients. +SourceLocation SourceManager::getImmediateSpellingLoc(SourceLocation Loc) const{ + if (Loc.isFileID()) return Loc; + std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc); + Loc = getSLocEntry(LocInfo.first).getInstantiation().getSpellingLoc(); + return Loc.getFileLocWithOffset(LocInfo.second); +} + + +/// getImmediateInstantiationRange - Loc is required to be an instantiation +/// location. Return the start/end of the instantiation information. +std::pair<SourceLocation,SourceLocation> +SourceManager::getImmediateInstantiationRange(SourceLocation Loc) const { + assert(Loc.isMacroID() && "Not an instantiation loc!"); + const InstantiationInfo &II = getSLocEntry(getFileID(Loc)).getInstantiation(); + return II.getInstantiationLocRange(); +} + +/// getInstantiationRange - Given a SourceLocation object, return the +/// range of tokens covered by the instantiation in the ultimate file. +std::pair<SourceLocation,SourceLocation> +SourceManager::getInstantiationRange(SourceLocation Loc) const { + if (Loc.isFileID()) return std::make_pair(Loc, Loc); + + std::pair<SourceLocation,SourceLocation> Res = + getImmediateInstantiationRange(Loc); + + // Fully resolve the start and end locations to their ultimate instantiation + // points. + while (!Res.first.isFileID()) + Res.first = getImmediateInstantiationRange(Res.first).first; + while (!Res.second.isFileID()) + Res.second = getImmediateInstantiationRange(Res.second).second; + return Res; +} + + + +//===----------------------------------------------------------------------===// +// Queries about the code at a SourceLocation. +//===----------------------------------------------------------------------===// + +/// getCharacterData - Return a pointer to the start of the specified location +/// in the appropriate MemoryBuffer. +const char *SourceManager::getCharacterData(SourceLocation SL, + bool *Invalid) const { + // Note that this is a hot function in the getSpelling() path, which is + // heavily used by -E mode. + std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(SL); + + // Note that calling 'getBuffer()' may lazily page in a source file. + bool CharDataInvalid = false; + const llvm::MemoryBuffer *Buffer + = getSLocEntry(LocInfo.first).getFile().getContentCache() + ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid); + if (Invalid) + *Invalid = CharDataInvalid; + return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second); +} + + +/// getColumnNumber - Return the column # for the specified file position. +/// this is significantly cheaper to compute than the line number. +unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos, + bool *Invalid) const { + bool MyInvalid = false; + const char *Buf = getBuffer(FID, &MyInvalid)->getBufferStart(); + if (Invalid) + *Invalid = MyInvalid; + + if (MyInvalid) + return 1; + + unsigned LineStart = FilePos; + while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r') + --LineStart; + return FilePos-LineStart+1; +} + +unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc, + bool *Invalid) const { + if (Loc.isInvalid()) return 0; + std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc); + return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); +} + +unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc, + bool *Invalid) const { + if (Loc.isInvalid()) return 0; + std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); +} + +static DISABLE_INLINE void +ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, + llvm::BumpPtrAllocator &Alloc, + const SourceManager &SM, bool &Invalid); +static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, + llvm::BumpPtrAllocator &Alloc, + const SourceManager &SM, bool &Invalid) { + // Note that calling 'getBuffer()' may lazily page in the file. + const MemoryBuffer *Buffer = FI->getBuffer(Diag, SM, SourceLocation(), + &Invalid); + if (Invalid) + return; + + // 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 = Alloc.Allocate<unsigned>(LineOffsets.size()); + std::copy(LineOffsets.begin(), LineOffsets.end(), FI->SourceLineCache); +} + +/// getLineNumber - Given a SourceLocation, return the spelling 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(FileID FID, unsigned FilePos, + bool *Invalid) const { + ContentCache *Content; + if (LastLineNoFileIDQuery == FID) + Content = LastLineNoContentCache; + else + Content = const_cast<ContentCache*>(getSLocEntry(FID) + .getFile().getContentCache()); + + // If this is the first use of line information for this buffer, compute the + /// SourceLineCache for it on demand. + if (Content->SourceLineCache == 0) { + bool MyInvalid = false; + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); + if (Invalid) + *Invalid = MyInvalid; + if (MyInvalid) + return 1; + } else if (Invalid) + *Invalid = false; + + // 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 = FilePos+1; + + // FIXME: I would like to be convinced that this code is worth being as + // complicated as it is, binary search isn't that slow. + // + // If it is worth being optimized, then in my opinion it could be more + // performant, simpler, and more obviously correct by just "galloping" outward + // from the queried file position. In fact, this could be incorporated into a + // generic algorithm such as lower_bound_with_hint. + // + // If someone gives me a test case where this matters, and I will do it! - DWD + + // 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 == FID) { + if (QueriedFilePos >= LastLineNoFilePos) { + // FIXME: Potential overflow? + 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 { + if (LastLineNoResult < Content->NumLines) + 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 = FID; + LastLineNoContentCache = Content; + LastLineNoFilePos = QueriedFilePos; + LastLineNoResult = LineNo; + return LineNo; +} + +unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc, + bool *Invalid) const { + if (Loc.isInvalid()) return 0; + std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + return getLineNumber(LocInfo.first, LocInfo.second); +} +unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc, + bool *Invalid) const { + if (Loc.isInvalid()) return 0; + std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc); + return getLineNumber(LocInfo.first, LocInfo.second); +} + +/// getFileCharacteristic - return the file characteristic of the specified +/// source location, indicating whether this is a normal file, a system +/// header, or an "implicit extern C" system header. +/// +/// This state can be modified with flags on GNU linemarker directives like: +/// # 4 "foo.h" 3 +/// which changes all source locations in the current file after that to be +/// considered to be from a system header. +SrcMgr::CharacteristicKind +SourceManager::getFileCharacteristic(SourceLocation Loc) const { + assert(!Loc.isInvalid() && "Can't get file characteristic of invalid loc!"); + std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile(); + + // If there are no #line directives in this file, just return the whole-file + // state. + if (!FI.hasLineDirectives()) + return FI.getFileCharacteristic(); + + assert(LineTable && "Can't have linetable entries without a LineTable!"); + // See if there is a #line directive before the location. + const LineEntry *Entry = + LineTable->FindNearestLineEntry(LocInfo.first.ID, LocInfo.second); + + // If this is before the first line marker, use the file characteristic. + if (!Entry) + return FI.getFileCharacteristic(); + + return Entry->FileKind; +} + +/// Return the filename or buffer identifier of the buffer the location is in. +/// Note that this name does not respect #line directives. Use getPresumedLoc +/// for normal clients. +const char *SourceManager::getBufferName(SourceLocation Loc, + bool *Invalid) const { + if (Loc.isInvalid()) return "<invalid loc>"; + + return getBuffer(getFileID(Loc), Invalid)->getBufferIdentifier(); +} + + +/// getPresumedLoc - This method returns the "presumed" location of a +/// SourceLocation specifies. A "presumed location" can be modified by #line +/// or GNU line marker directives. This provides a view on the data that a +/// user should see in diagnostics, for example. +/// +/// Note that a presumed location is always given as the instantiation point +/// of an instantiation location, not at the spelling location. +PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { + if (Loc.isInvalid()) return PresumedLoc(); + + // Presumed locations are always for instantiation points. + std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + + const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile(); + const SrcMgr::ContentCache *C = FI.getContentCache(); + + // To get the source name, first consult the FileEntry (if one exists) + // before the MemBuffer as this will avoid unnecessarily paging in the + // MemBuffer. + const char *Filename; + if (C->Entry) + Filename = C->Entry->getName(); + else + Filename = C->getBuffer(Diag, *this)->getBufferIdentifier(); + unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second); + unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second); + SourceLocation IncludeLoc = FI.getIncludeLoc(); + + // If we have #line directives in this file, update and overwrite the physical + // location info if appropriate. + if (FI.hasLineDirectives()) { + assert(LineTable && "Can't have linetable entries without a LineTable!"); + // See if there is a #line directive before this. If so, get it. + if (const LineEntry *Entry = + LineTable->FindNearestLineEntry(LocInfo.first.ID, LocInfo.second)) { + // If the LineEntry indicates a filename, use it. + if (Entry->FilenameID != -1) + Filename = LineTable->getFilename(Entry->FilenameID); + + // Use the line number specified by the LineEntry. This line number may + // be multiple lines down from the line entry. Add the difference in + // physical line numbers from the query point and the line marker to the + // total. + unsigned MarkerLineNo = getLineNumber(LocInfo.first, Entry->FileOffset); + LineNo = Entry->LineNo + (LineNo-MarkerLineNo-1); + + // Note that column numbers are not molested by line markers. + + // Handle virtual #include manipulation. + if (Entry->IncludeOffset) { + IncludeLoc = getLocForStartOfFile(LocInfo.first); + IncludeLoc = IncludeLoc.getFileLocWithOffset(Entry->IncludeOffset); + } + } + } + + return PresumedLoc(Filename, LineNo, ColNo, IncludeLoc); +} + +//===----------------------------------------------------------------------===// +// Other miscellaneous methods. +//===----------------------------------------------------------------------===// + +/// \brief Get the source location for the given file:line:col triplet. +/// +/// If the source file is included multiple times, the source location will +/// be based upon the first inclusion. +SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, + unsigned Line, unsigned Col) const { + assert(SourceFile && "Null source file!"); + assert(Line && Col && "Line and column should start from 1!"); + + fileinfo_iterator FI = FileInfos.find(SourceFile); + if (FI == FileInfos.end()) + return SourceLocation(); + ContentCache *Content = FI->second; + + // If this is the first use of line information for this buffer, compute the + /// SourceLineCache for it on demand. + if (Content->SourceLineCache == 0) { + bool MyInvalid = false; + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); + if (MyInvalid) + return SourceLocation(); + } + + // Find the first file ID that corresponds to the given file. + FileID FirstFID; + + // First, check the main file ID, since it is common to look for a + // location in the main file. + if (!MainFileID.isInvalid()) { + const SLocEntry &MainSLoc = getSLocEntry(MainFileID); + if (MainSLoc.isFile() && MainSLoc.getFile().getContentCache() == Content) + FirstFID = MainFileID; + } + + if (FirstFID.isInvalid()) { + // The location we're looking for isn't in the main file; look + // through all of the source locations. + for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) { + const SLocEntry &SLoc = getSLocEntry(I); + if (SLoc.isFile() && SLoc.getFile().getContentCache() == Content) { + FirstFID = FileID::get(I); + break; + } + } + } + + if (FirstFID.isInvalid()) + return SourceLocation(); + + if (Line > Content->NumLines) { + unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize(); + if (Size > 0) + --Size; + return getLocForStartOfFile(FirstFID).getFileLocWithOffset(Size); + } + + unsigned FilePos = Content->SourceLineCache[Line - 1]; + const char *Buf = Content->getBuffer(Diag, *this)->getBufferStart() + FilePos; + unsigned BufLength = Content->getBuffer(Diag, *this)->getBufferEnd() - Buf; + unsigned i = 0; + + // Check that the given column is valid. + while (i < BufLength-1 && i < Col-1 && Buf[i] != '\n' && Buf[i] != '\r') + ++i; + if (i < Col-1) + return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + i); + + return getLocForStartOfFile(FirstFID).getFileLocWithOffset(FilePos + Col - 1); +} + +/// Given a decomposed source location, move it up the include/instantiation +/// stack to the parent source location. If this is possible, return the +/// decomposed version of the parent in Loc and return false. If Loc is the +/// top-level entry, return true and don't modify it. +static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc, + const SourceManager &SM) { + SourceLocation UpperLoc; + const SrcMgr::SLocEntry &Entry = SM.getSLocEntry(Loc.first); + if (Entry.isInstantiation()) + UpperLoc = Entry.getInstantiation().getInstantiationLocStart(); + else + UpperLoc = Entry.getFile().getIncludeLoc(); + + if (UpperLoc.isInvalid()) + return true; // We reached the top. + + Loc = SM.getDecomposedLoc(UpperLoc); + return false; +} + + +/// \brief Determines the order of 2 source locations in the translation unit. +/// +/// \returns true if LHS source location comes before RHS, false otherwise. +bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, + SourceLocation RHS) const { + assert(LHS.isValid() && RHS.isValid() && "Passed invalid source location!"); + if (LHS == RHS) + return false; + + std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS); + std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS); + + // If the source locations are in the same file, just compare offsets. + if (LOffs.first == ROffs.first) + return LOffs.second < ROffs.second; + + // If we are comparing a source location with multiple locations in the same + // file, we get a big win by caching the result. + if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first)) + return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second); + + // Okay, we missed in the cache, start updating the cache for this query. + IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first); + + // "Traverse" the include/instantiation stacks of both locations and try to + // find a common "ancestor". FileIDs build a tree-like structure that + // reflects the #include hierarchy, and this algorithm needs to find the + // nearest common ancestor between the two locations. For example, if you + // have a.c that includes b.h and c.h, and are comparing a location in b.h to + // a location in c.h, we need to find that their nearest common ancestor is + // a.c, and compare the locations of the two #includes to find their relative + // ordering. + // + // SourceManager assigns FileIDs in order of parsing. This means that an + // includee always has a larger FileID than an includer. While you might + // think that we could just compare the FileID's here, that doesn't work to + // compare a point at the end of a.c with a point within c.h. Though c.h has + // a larger FileID, we have to compare the include point of c.h to the + // location in a.c. + // + // Despite not being able to directly compare FileID's, we can tell that a + // larger FileID is necessarily more deeply nested than a lower one and use + // this information to walk up the tree to the nearest common ancestor. + do { + // If LOffs is larger than ROffs, then LOffs must be more deeply nested than + // ROffs, walk up the #include chain. + if (LOffs.first.ID > ROffs.first.ID) { + if (MoveUpIncludeHierarchy(LOffs, *this)) + break; // We reached the top. + + } else { + // Otherwise, ROffs is larger than LOffs, so ROffs must be more deeply + // nested than LOffs, walk up the #include chain. + if (MoveUpIncludeHierarchy(ROffs, *this)) + break; // We reached the top. + } + } while (LOffs.first != ROffs.first); + + // If we exited because we found a nearest common ancestor, compare the + // locations within the common file and cache them. + if (LOffs.first == ROffs.first) { + IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second); + return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second); + } + + // There is no common ancestor, most probably because one location is in the + // predefines buffer or a PCH file. + // FIXME: We should rearrange the external interface so this simply never + // happens; it can't conceptually happen. Also see PR5662. + IsBeforeInTUCache.setQueryFIDs(FileID(), FileID()); // Don't try caching. + + // Zip both entries up to the top level record. + while (!MoveUpIncludeHierarchy(LOffs, *this)) /*empty*/; + while (!MoveUpIncludeHierarchy(ROffs, *this)) /*empty*/; + + // If exactly one location is a memory buffer, assume it preceeds the other. + + // Strip off macro instantation locations, going up to the top-level File + // SLocEntry. + bool LIsMB = getFileEntryForID(LOffs.first) == 0; + bool RIsMB = getFileEntryForID(ROffs.first) == 0; + if (LIsMB != RIsMB) + return LIsMB; + + // Otherwise, just assume FileIDs were created in order. + return LOffs.first < ROffs.first; +} + +/// PrintStats - Print statistics to stderr. +/// +void SourceManager::PrintStats() const { + llvm::errs() << "\n*** Source Manager Stats:\n"; + llvm::errs() << FileInfos.size() << " files mapped, " << MemBufferInfos.size() + << " mem buffers mapped.\n"; + llvm::errs() << SLocEntryTable.size() << " SLocEntry's allocated, " + << NextOffset << "B of Sloc address space used.\n"; + + unsigned NumLineNumsComputed = 0; + unsigned NumFileBytesMapped = 0; + for (fileinfo_iterator I = fileinfo_begin(), E = fileinfo_end(); I != E; ++I){ + NumLineNumsComputed += I->second->SourceLineCache != 0; + NumFileBytesMapped += I->second->getSizeBytesMapped(); + } + + llvm::errs() << NumFileBytesMapped << " bytes of files mapped, " + << NumLineNumsComputed << " files with line #'s computed.\n"; + llvm::errs() << "FileID scans: " << NumLinearScans << " linear, " + << NumBinaryProbes << " binary.\n"; +} + +ExternalSLocEntrySource::~ExternalSLocEntrySource() { } diff --git a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp new file mode 100644 index 0000000..6692e64 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp @@ -0,0 +1,384 @@ +//===--- 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/LangOptions.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +#include <cstdlib> +using namespace clang; + +// TargetInfo Constructor. +TargetInfo::TargetInfo(const std::string &T) : Triple(T) { + // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or + // SPARC. These should be overridden by concrete targets as needed. + TLSSupported = true; + NoAsmVariants = false; + PointerWidth = PointerAlign = 32; + IntWidth = IntAlign = 32; + LongWidth = LongAlign = 32; + LongLongWidth = LongLongAlign = 64; + FloatWidth = 32; + FloatAlign = 32; + DoubleWidth = 64; + DoubleAlign = 64; + LongDoubleWidth = 64; + LongDoubleAlign = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntMaxType = SignedLongLong; + UIntMaxType = UnsignedLongLong; + IntPtrType = SignedLong; + WCharType = SignedInt; + WIntType = SignedInt; + Char16Type = UnsignedShort; + Char32Type = UnsignedInt; + Int64Type = SignedLongLong; + SigAtomicType = SignedInt; + UseBitFieldTypeAlignment = true; + FloatFormat = &llvm::APFloat::IEEEsingle; + DoubleFormat = &llvm::APFloat::IEEEdouble; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; + DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-n32"; + UserLabelPrefix = "_"; + HasAlignMac68kSupport = false; +} + +// Out of line virtual dtor for TargetInfo. +TargetInfo::~TargetInfo() {} + +/// getTypeName - Return the user string for the specified integer type enum. +/// For example, SignedShort -> "short". +const char *TargetInfo::getTypeName(IntType T) { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: return "short"; + case UnsignedShort: return "unsigned short"; + case SignedInt: return "int"; + case UnsignedInt: return "unsigned int"; + case SignedLong: return "long int"; + case UnsignedLong: return "long unsigned int"; + case SignedLongLong: return "long long int"; + case UnsignedLongLong: return "long long unsigned int"; + } +} + +/// getTypeConstantSuffix - Return the constant suffix for the specified +/// integer type enum. For example, SignedLong -> "L". +const char *TargetInfo::getTypeConstantSuffix(IntType T) { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: + case SignedInt: return ""; + case SignedLong: return "L"; + case SignedLongLong: return "LL"; + case UnsignedShort: + case UnsignedInt: return "U"; + case UnsignedLong: return "UL"; + case UnsignedLongLong: return "ULL"; + } +} + +/// getTypeWidth - Return the width (in bits) of the specified integer type +/// enum. For example, SignedInt -> getIntWidth(). +unsigned TargetInfo::getTypeWidth(IntType T) const { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: + case UnsignedShort: return getShortWidth(); + case SignedInt: + case UnsignedInt: return getIntWidth(); + case SignedLong: + case UnsignedLong: return getLongWidth(); + case SignedLongLong: + case UnsignedLongLong: return getLongLongWidth(); + }; +} + +/// getTypeAlign - Return the alignment (in bits) of the specified integer type +/// enum. For example, SignedInt -> getIntAlign(). +unsigned TargetInfo::getTypeAlign(IntType T) const { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: + case UnsignedShort: return getShortAlign(); + case SignedInt: + case UnsignedInt: return getIntAlign(); + case SignedLong: + case UnsignedLong: return getLongAlign(); + case SignedLongLong: + case UnsignedLongLong: return getLongLongAlign(); + }; +} + +/// isTypeSigned - Return whether an integer types is signed. Returns true if +/// the type is signed; false otherwise. +bool TargetInfo::isTypeSigned(IntType T) const { + switch (T) { + default: assert(0 && "not an integer!"); + case SignedShort: + case SignedInt: + case SignedLong: + case SignedLongLong: + return true; + case UnsignedShort: + case UnsignedInt: + case UnsignedLong: + case UnsignedLongLong: + return false; + }; +} + +/// setForcedLangOptions - Set forced language options. +/// Apply changes to the target information with respect to certain +/// language options which change the target configuration. +void TargetInfo::setForcedLangOptions(LangOptions &Opts) { + if (Opts.NoBitFieldTypeAlign) + UseBitFieldTypeAlignment = false; + if (Opts.ShortWChar) + WCharType = UnsignedShort; +} + +//===----------------------------------------------------------------------===// + + +static llvm::StringRef removeGCCRegisterPrefix(llvm::StringRef Name) { + if (Name[0] == '%' || Name[0] == '#') + Name = Name.substr(1); + + return 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(llvm::StringRef Name) const { + if (Name.empty()) + return false; + + const char * const *Names; + unsigned NumNames; + + // Get rid of any register prefix. + Name = removeGCCRegisterPrefix(Name); + + if (Name == "memory" || Name == "cc") + return true; + + getGCCRegNames(Names, NumNames); + + // If we have a number it maps to an entry in the register name array. + if (isdigit(Name[0])) { + int n; + if (!Name.getAsInteger(0, n)) + return n >= 0 && (unsigned)n < NumNames; + } + + // Check register names. + for (unsigned i = 0; i < NumNames; i++) { + if (Name == Names[i]) + 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 (Aliases[i].Aliases[j] == Name) + return true; + } + } + + return false; +} + +llvm::StringRef +TargetInfo::getNormalizedGCCRegisterName(llvm::StringRef Name) const { + assert(isValidGCCRegisterName(Name) && "Invalid register passed in"); + + // Get rid of any register prefix. + Name = removeGCCRegisterPrefix(Name); + + const char * const *Names; + unsigned NumNames; + + getGCCRegNames(Names, NumNames); + + // First, check if we have a number. + if (isdigit(Name[0])) { + int n; + if (!Name.getAsInteger(0, n)) { + 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 (Aliases[i].Aliases[j] == Name) + return Aliases[i].Register; + } + } + + return Name; +} + +bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { + const char *Name = Info.getConstraintStr().c_str(); + // An output constraint must start with '=' or '+' + if (*Name != '=' && *Name != '+') + return false; + + if (*Name == '+') + Info.setIsReadWrite(); + + Name++; + while (*Name) { + switch (*Name) { + default: + if (!validateAsmConstraint(Name, Info)) { + // FIXME: We temporarily return false + // so we can add more constraints as we hit it. + // Eventually, an unknown constraint should just be treated as 'g'. + return false; + } + case '&': // early clobber. + break; + case '%': // commutative. + // FIXME: Check that there is a another register after this one. + break; + case 'r': // general register. + Info.setAllowsRegister(); + break; + case 'm': // memory operand. + Info.setAllowsMemory(); + break; + case 'g': // general register, memory operand or immediate integer. + case 'X': // any operand. + Info.setAllowsRegister(); + Info.setAllowsMemory(); + break; + } + + Name++; + } + + return true; +} + +bool TargetInfo::resolveSymbolicName(const char *&Name, + ConstraintInfo *OutputConstraints, + unsigned NumOutputs, + unsigned &Index) const { + assert(*Name == '[' && "Symbolic name did not start with '['"); + Name++; + const char *Start = Name; + while (*Name && *Name != ']') + Name++; + + if (!*Name) { + // Missing ']' + return false; + } + + std::string SymbolicName(Start, Name - Start); + + for (Index = 0; Index != NumOutputs; ++Index) + if (SymbolicName == OutputConstraints[Index].getName()) + return true; + + return false; +} + +bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, + unsigned NumOutputs, + ConstraintInfo &Info) const { + const char *Name = Info.ConstraintStr.c_str(); + + 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; + + // The constraint should have the same info as the respective + // output constraint. + Info.setTiedOperand(i, OutputConstraints[i]); + } else if (!validateAsmConstraint(Name, Info)) { + // FIXME: This error return is in place temporarily so we can + // add more constraints as we hit it. Eventually, an unknown + // constraint should just be treated as 'g'. + return false; + } + break; + case '[': { + unsigned Index = 0; + if (!resolveSymbolicName(Name, OutputConstraints, NumOutputs, Index)) + return false; + + break; + } + case '%': // commutative + // FIXME: Fail if % is used with the last operand. + break; + case 'i': // immediate integer. + case 'n': // immediate integer with a known value. + break; + case 'I': // Various constant constraints with target-specific meanings. + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + break; + case 'r': // general register. + Info.setAllowsRegister(); + break; + case 'm': // memory operand. + case 'o': // offsettable memory operand + case 'V': // non-offsettable memory operand + Info.setAllowsMemory(); + break; + case 'g': // general register, memory operand or immediate integer. + case 'X': // any operand. + Info.setAllowsRegister(); + Info.setAllowsMemory(); + break; + } + + Name++; + } + + return true; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp new file mode 100644 index 0000000..92fd417 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp @@ -0,0 +1,2476 @@ +//===--- 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/Basic/TargetInfo.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/MC/MCSectionMachO.h" +#include <algorithm> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Common code shared among targets. +//===----------------------------------------------------------------------===// + +/// DefineStd - Define a macro name and standard variants. For example if +/// MacroName is "unix", then this will define "__unix", "__unix__", and "unix" +/// when in GNU mode. +static void DefineStd(MacroBuilder &Builder, llvm::StringRef MacroName, + const LangOptions &Opts) { + assert(MacroName[0] != '_' && "Identifier should be in the user's namespace"); + + // If in GNU mode (e.g. -std=gnu99 but not -std=c99) define the raw identifier + // in the user's namespace. + if (Opts.GNUMode) + Builder.defineMacro(MacroName); + + // Define __unix. + Builder.defineMacro("__" + MacroName); + + // Define __unix__. + Builder.defineMacro("__" + MacroName + "__"); +} + +//===----------------------------------------------------------------------===// +// Defines specific to certain operating systems. +//===----------------------------------------------------------------------===// + +namespace { +template<typename TgtInfo> +class OSTargetInfo : public TgtInfo { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const=0; +public: + OSTargetInfo(const std::string& triple) : TgtInfo(triple) {} + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + TgtInfo::getTargetDefines(Opts, Builder); + getOSDefines(Opts, TgtInfo::getTriple(), Builder); + } + +}; +} // end anonymous namespace + + +static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, + const llvm::Triple &Triple) { + Builder.defineMacro("__APPLE_CC__", "5621"); + Builder.defineMacro("__APPLE__"); + Builder.defineMacro("__MACH__"); + Builder.defineMacro("OBJC_NEW_PROPERTIES"); + + // __weak is always defined, for use in blocks and with objc pointers. + Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); + + // Darwin defines __strong even in C mode (just to nothing). + if (!Opts.ObjC1 || Opts.getGCMode() == LangOptions::NonGC) + Builder.defineMacro("__strong", ""); + else + Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))"); + + if (Opts.Static) + Builder.defineMacro("__STATIC__"); + else + Builder.defineMacro("__DYNAMIC__"); + + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + + // Get the OS version number from the triple. + unsigned Maj, Min, Rev; + + // If no version was given, default to to 10.4.0, for simplifying tests. + if (Triple.getOSName() == "darwin") { + Min = Rev = 0; + Maj = 8; + } else + Triple.getDarwinNumber(Maj, Min, Rev); + + // Set the appropriate OS version define. + if (Triple.getEnvironmentName() == "iphoneos") { + assert(Maj < 10 && Min < 99 && Rev < 99 && "Invalid version!"); + char Str[6]; + Str[0] = '0' + Maj; + Str[1] = '0' + (Min / 10); + Str[2] = '0' + (Min % 10); + Str[3] = '0' + (Rev / 10); + Str[4] = '0' + (Rev % 10); + Str[5] = '\0'; + Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str); + } else { + // For historical reasons that make little sense, the version passed here is + // the "darwin" version, which drops the 10 and offsets by 4. + Rev = Min; + Min = Maj - 4; + Maj = 10; + + assert(Triple.getEnvironmentName().empty() && "Invalid environment!"); + assert(Maj < 99 && Min < 10 && Rev < 10 && "Invalid version!"); + char Str[5]; + Str[0] = '0' + (Maj / 10); + Str[1] = '0' + (Maj % 10); + Str[2] = '0' + Min; + Str[3] = '0' + Rev; + Str[4] = '\0'; + Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str); + } +} + +namespace { +template<typename Target> +class DarwinTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + getDarwinDefines(Builder, Opts, Triple); + } + +public: + DarwinTargetInfo(const std::string& triple) : + OSTargetInfo<Target>(triple) { + this->TLSSupported = false; + } + + virtual std::string isValidSectionSpecifier(llvm::StringRef SR) const { + // Let MCSectionMachO validate this. + llvm::StringRef Segment, Section; + unsigned TAA, StubSize; + return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section, + TAA, StubSize); + } +}; + + +// DragonFlyBSD Target +template<typename Target> +class DragonFlyBSDTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + // DragonFly defines; list based off of gcc output + Builder.defineMacro("__DragonFly__"); + Builder.defineMacro("__DragonFly_cc_version", "100001"); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); + Builder.defineMacro("__tune_i386__"); + DefineStd(Builder, "unix", Opts); + } +public: + DragonFlyBSDTargetInfo(const std::string &triple) + : OSTargetInfo<Target>(triple) {} +}; + +// FreeBSD Target +template<typename Target> +class FreeBSDTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + // FreeBSD defines; list based off of gcc output + + // FIXME: Move version number handling to llvm::Triple. + llvm::StringRef Release = Triple.getOSName().substr(strlen("freebsd"), 1); + + Builder.defineMacro("__FreeBSD__", Release); + Builder.defineMacro("__FreeBSD_cc_version", Release + "00001"); + Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + } +public: + FreeBSDTargetInfo(const std::string &triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + } +}; + +// Linux target +template<typename Target> +class LinuxTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + // Linux defines; list based off of gcc output + DefineStd(Builder, "unix", Opts); + DefineStd(Builder, "linux", Opts); + Builder.defineMacro("__gnu_linux__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +public: + LinuxTargetInfo(const std::string& triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + } +}; + +// NetBSD Target +template<typename Target> +class NetBSDTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + // NetBSD defines; list based off of gcc output + Builder.defineMacro("__NetBSD__"); + Builder.defineMacro("__unix__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_POSIX_THREADS"); + } +public: + NetBSDTargetInfo(const std::string &triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + } +}; + +// OpenBSD Target +template<typename Target> +class OpenBSDTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + // OpenBSD defines; list based off of gcc output + + Builder.defineMacro("__OpenBSD__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_POSIX_THREADS"); + } +public: + OpenBSDTargetInfo(const std::string &triple) + : OSTargetInfo<Target>(triple) {} +}; + +// PSP Target +template<typename Target> +class PSPTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + // PSP defines; list based on the output of the pspdev gcc toolchain. + Builder.defineMacro("PSP"); + Builder.defineMacro("_PSP"); + Builder.defineMacro("__psp__"); + Builder.defineMacro("__ELF__"); + } +public: + PSPTargetInfo(const std::string& triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + } +}; + +// PS3 PPU Target +template<typename Target> +class PS3PPUTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + // PS3 PPU defines. + Builder.defineMacro("__PPC__"); + Builder.defineMacro("__PPU__"); + Builder.defineMacro("__CELLOS_LV2__"); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__LP32__"); + } +public: + PS3PPUTargetInfo(const std::string& triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + this->LongWidth = this->LongAlign = this->PointerWidth = this->PointerAlign = 32; + this->SizeType = TargetInfo::UnsignedInt; + } +}; + +// FIXME: Need a real SPU target. +// PS3 SPU Target +template<typename Target> +class PS3SPUTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + // PS3 PPU defines. + Builder.defineMacro("__SPU__"); + Builder.defineMacro("__ELF__"); + } +public: + PS3SPUTargetInfo(const std::string& triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + } +}; + +// AuroraUX target +template<typename Target> +class AuroraUXTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + DefineStd(Builder, "sun", Opts); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__svr4__"); + Builder.defineMacro("__SVR4"); + } +public: + AuroraUXTargetInfo(const std::string& triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + this->WCharType = this->SignedLong; + // FIXME: WIntType should be SignedLong + } +}; + +// Solaris target +template<typename Target> +class SolarisTargetInfo : public OSTargetInfo<Target> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + DefineStd(Builder, "sun", Opts); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__svr4__"); + Builder.defineMacro("__SVR4"); + } +public: + SolarisTargetInfo(const std::string& triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + this->WCharType = this->SignedLong; + // FIXME: WIntType should be SignedLong + } +}; +} // end anonymous namespace. + +//===----------------------------------------------------------------------===// +// Specific target implementations. +//===----------------------------------------------------------------------===// + +namespace { +// PPC abstract base class +class PPCTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + static const char * const GCCRegNames[]; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + +public: + PPCTargetInfo(const std::string& triple) : TargetInfo(triple) {} + + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + Records = BuiltinInfo; + NumRecords = clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const; + + virtual const char *getVAListDeclaration() const { + return "typedef char* __builtin_va_list;"; + // This is the right definition for ABI/V4: System V.4/eabi. + /*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];";*/ + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const; + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: return false; + case 'O': // Zero + return true; + case 'b': // Base register + case 'f': // Floating point register + Info.setAllowsRegister(); + return true; + } + } + virtual const char *getClobbers() const { + return ""; + } +}; + +const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false }, +#include "clang/Basic/BuiltinsPPC.def" +}; + + +/// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific +/// #defines that are not tied to a specific subtarget. +void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Target identification. + Builder.defineMacro("__ppc__"); + Builder.defineMacro("_ARCH_PPC"); + Builder.defineMacro("__powerpc__"); + Builder.defineMacro("__POWERPC__"); + if (PointerWidth == 64) { + Builder.defineMacro("_ARCH_PPC64"); + Builder.defineMacro("_LP64"); + Builder.defineMacro("__LP64__"); + Builder.defineMacro("__powerpc64__"); + Builder.defineMacro("__ppc64__"); + } else { + Builder.defineMacro("__ppc__"); + } + + // Target properties. + Builder.defineMacro("_BIG_ENDIAN"); + Builder.defineMacro("__BIG_ENDIAN__"); + + // Subtarget options. + Builder.defineMacro("__NATURAL_ALIGNMENT__"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + // FIXME: Should be controlled by command line option. + Builder.defineMacro("__LONG_DOUBLE_128__"); + + if (Opts.AltiVec) { + Builder.defineMacro("__VEC__", "10206"); + Builder.defineMacro("__ALTIVEC__"); + } +} + + +const char * const PPCTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + "mq", "lr", "ctr", "ap", + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", + "xer", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", + "vrsave", "vscr", + "spe_acc", "spefscr", + "sfp" +}; + +void PPCTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} + +const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = { + // While some of these aliases do map to different registers + // they still share the same register name. + { { "0" }, "r0" }, + { { "1"}, "r1" }, + { { "2" }, "r2" }, + { { "3" }, "r3" }, + { { "4" }, "r4" }, + { { "5" }, "r5" }, + { { "6" }, "r6" }, + { { "7" }, "r7" }, + { { "8" }, "r8" }, + { { "9" }, "r9" }, + { { "10" }, "r10" }, + { { "11" }, "r11" }, + { { "12" }, "r12" }, + { { "13" }, "r13" }, + { { "14" }, "r14" }, + { { "15" }, "r15" }, + { { "16" }, "r16" }, + { { "17" }, "r17" }, + { { "18" }, "r18" }, + { { "19" }, "r19" }, + { { "20" }, "r20" }, + { { "21" }, "r21" }, + { { "22" }, "r22" }, + { { "23" }, "r23" }, + { { "24" }, "r24" }, + { { "25" }, "r25" }, + { { "26" }, "r26" }, + { { "27" }, "r27" }, + { { "28" }, "r28" }, + { { "29" }, "r29" }, + { { "30" }, "r30" }, + { { "31" }, "r31" }, + { { "fr0" }, "f0" }, + { { "fr1" }, "f1" }, + { { "fr2" }, "f2" }, + { { "fr3" }, "f3" }, + { { "fr4" }, "f4" }, + { { "fr5" }, "f5" }, + { { "fr6" }, "f6" }, + { { "fr7" }, "f7" }, + { { "fr8" }, "f8" }, + { { "fr9" }, "f9" }, + { { "fr10" }, "f10" }, + { { "fr11" }, "f11" }, + { { "fr12" }, "f12" }, + { { "fr13" }, "f13" }, + { { "fr14" }, "f14" }, + { { "fr15" }, "f15" }, + { { "fr16" }, "f16" }, + { { "fr17" }, "f17" }, + { { "fr18" }, "f18" }, + { { "fr19" }, "f19" }, + { { "fr20" }, "f20" }, + { { "fr21" }, "f21" }, + { { "fr22" }, "f22" }, + { { "fr23" }, "f23" }, + { { "fr24" }, "f24" }, + { { "fr25" }, "f25" }, + { { "fr26" }, "f26" }, + { { "fr27" }, "f27" }, + { { "fr28" }, "f28" }, + { { "fr29" }, "f29" }, + { { "fr30" }, "f30" }, + { { "fr31" }, "f31" }, + { { "cc" }, "cr0" }, +}; + +void PPCTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} +} // end anonymous namespace. + +namespace { +class PPC32TargetInfo : public PPCTargetInfo { +public: + PPC32TargetInfo(const std::string &triple) : PPCTargetInfo(triple) { + DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32"; + + if (getTriple().getOS() == llvm::Triple::FreeBSD) + this->SizeType = TargetInfo::UnsignedInt; + } +}; +} // end anonymous namespace. + +namespace { +class PPC64TargetInfo : public PPCTargetInfo { +public: + PPC64TargetInfo(const std::string& triple) : PPCTargetInfo(triple) { + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + Int64Type = SignedLong; + DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64"; + } +}; +} // end anonymous namespace. + +namespace { +// MBlaze abstract base class +class MBlazeTargetInfo : public TargetInfo { + static const char * const GCCRegNames[]; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + +public: + MBlazeTargetInfo(const std::string& triple) : TargetInfo(triple) { + DescriptionString = "E-p:32:32-i8:8:8-i16:16:16-i64:32:32-f64:32:32-" + "v64:32:32-v128:32:32-n32"; + } + + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement. + Records = 0; + NumRecords = 0; + } + + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const; + + virtual const char *getVAListDeclaration() const { + return "typedef char* __builtin_va_list;"; + } + virtual const char *getTargetPrefix() const { + return "mblaze"; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const; + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: return false; + case 'O': // Zero + return true; + case 'b': // Base register + case 'f': // Floating point register + Info.setAllowsRegister(); + return true; + } + } + virtual const char *getClobbers() const { + return ""; + } +}; + +/// MBlazeTargetInfo::getTargetDefines - Return a set of the MBlaze-specific +/// #defines that are not tied to a specific subtarget. +void MBlazeTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Target identification. + Builder.defineMacro("__microblaze__"); + Builder.defineMacro("_ARCH_MICROBLAZE"); + Builder.defineMacro("__MICROBLAZE__"); + + // Target properties. + Builder.defineMacro("_BIG_ENDIAN"); + Builder.defineMacro("__BIG_ENDIAN__"); + + // Subtarget options. + Builder.defineMacro("__REGISTER_PREFIX__", ""); +} + + +const char * const MBlazeTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", + "hi", "lo", "accum","rmsr", "$fcc1","$fcc2","$fcc3","$fcc4", + "$fcc5","$fcc6","$fcc7","$ap", "$rap", "$frp" +}; + +void MBlazeTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} + +const TargetInfo::GCCRegAlias MBlazeTargetInfo::GCCRegAliases[] = { + { {"f0"}, "r0" }, + { {"f1"}, "r1" }, + { {"f2"}, "r2" }, + { {"f3"}, "r3" }, + { {"f4"}, "r4" }, + { {"f5"}, "r5" }, + { {"f6"}, "r6" }, + { {"f7"}, "r7" }, + { {"f8"}, "r8" }, + { {"f9"}, "r9" }, + { {"f10"}, "r10" }, + { {"f11"}, "r11" }, + { {"f12"}, "r12" }, + { {"f13"}, "r13" }, + { {"f14"}, "r14" }, + { {"f15"}, "r15" }, + { {"f16"}, "r16" }, + { {"f17"}, "r17" }, + { {"f18"}, "r18" }, + { {"f19"}, "r19" }, + { {"f20"}, "r20" }, + { {"f21"}, "r21" }, + { {"f22"}, "r22" }, + { {"f23"}, "r23" }, + { {"f24"}, "r24" }, + { {"f25"}, "r25" }, + { {"f26"}, "r26" }, + { {"f27"}, "r27" }, + { {"f28"}, "r28" }, + { {"f29"}, "r29" }, + { {"f30"}, "r30" }, + { {"f31"}, "r31" }, +}; + +void MBlazeTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} +} // end anonymous namespace. + +namespace { +// Namespace for x86 abstract base class +const Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false }, +#include "clang/Basic/BuiltinsX86.def" +}; + +static const char* const 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" +}; + +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" }, + { { "edi", "rdi" }, "di" }, + { { "esp", "rsp" }, "sp" }, + { { "ebp", "rbp" }, "bp" }, +}; + +// X86 target abstract base class; x86-32 and x86-64 are very close, so +// most of the implementation can be shared. +class X86TargetInfo : public TargetInfo { + enum X86SSEEnum { + NoMMXSSE, MMX, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42 + } SSELevel; + enum AMD3DNowEnum { + NoAMD3DNow, AMD3DNow, AMD3DNowAthlon + } AMD3DNowLevel; + + bool HasAES; + +public: + X86TargetInfo(const std::string& triple) + : TargetInfo(triple), SSELevel(NoMMXSSE), AMD3DNowLevel(NoAMD3DNow), + HasAES(false) { + LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + Records = BuiltinInfo; + NumRecords = clang::X86::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); + } + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const; + virtual std::string convertConstraint(const char Constraint) const; + virtual const char *getClobbers() const { + return "~{dirflag},~{fpsr},~{flags}"; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const; + virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, + const std::string &Name, + bool Enabled) const; + virtual void getDefaultFeatures(const std::string &CPU, + llvm::StringMap<bool> &Features) const; + virtual void HandleTargetFeatures(std::vector<std::string> &Features); +}; + +void X86TargetInfo::getDefaultFeatures(const std::string &CPU, + llvm::StringMap<bool> &Features) const { + // FIXME: This should not be here. + Features["3dnow"] = false; + Features["3dnowa"] = false; + Features["mmx"] = false; + Features["sse"] = false; + Features["sse2"] = false; + Features["sse3"] = false; + Features["ssse3"] = false; + Features["sse41"] = false; + Features["sse42"] = false; + Features["aes"] = false; + + // LLVM does not currently recognize this. + // Features["sse4a"] = false; + + // FIXME: This *really* should not be here. + + // X86_64 always has SSE2. + if (PointerWidth == 64) + Features["sse2"] = Features["sse"] = Features["mmx"] = true; + + if (CPU == "generic" || CPU == "i386" || CPU == "i486" || CPU == "i586" || + CPU == "pentium" || CPU == "i686" || CPU == "pentiumpro") + ; + else if (CPU == "pentium-mmx" || CPU == "pentium2") + setFeatureEnabled(Features, "mmx", true); + else if (CPU == "pentium3") + setFeatureEnabled(Features, "sse", true); + else if (CPU == "pentium-m" || CPU == "pentium4" || CPU == "x86-64") + setFeatureEnabled(Features, "sse2", true); + else if (CPU == "yonah" || CPU == "prescott" || CPU == "nocona") + setFeatureEnabled(Features, "sse3", true); + else if (CPU == "core2") + setFeatureEnabled(Features, "ssse3", true); + else if (CPU == "penryn") { + setFeatureEnabled(Features, "sse4", true); + Features["sse42"] = false; + } else if (CPU == "atom") + setFeatureEnabled(Features, "sse3", true); + else if (CPU == "corei7") { + setFeatureEnabled(Features, "sse4", true); + setFeatureEnabled(Features, "aes", true); + } + else if (CPU == "k6" || CPU == "winchip-c6") + setFeatureEnabled(Features, "mmx", true); + else if (CPU == "k6-2" || CPU == "k6-3" || CPU == "athlon" || + CPU == "athlon-tbird" || CPU == "winchip2" || CPU == "c3") { + setFeatureEnabled(Features, "mmx", true); + setFeatureEnabled(Features, "3dnow", true); + } else if (CPU == "athlon-4" || CPU == "athlon-xp" || CPU == "athlon-mp") { + setFeatureEnabled(Features, "sse", true); + setFeatureEnabled(Features, "3dnowa", true); + } else if (CPU == "k8" || CPU == "opteron" || CPU == "athlon64" || + CPU == "athlon-fx") { + setFeatureEnabled(Features, "sse2", true); + setFeatureEnabled(Features, "3dnowa", true); + } else if (CPU == "c3-2") + setFeatureEnabled(Features, "sse", true); +} + +bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, + const std::string &Name, + bool Enabled) const { + // FIXME: This *really* should not be here. We need some way of translating + // options into llvm subtarget features. + if (!Features.count(Name) && + (Name != "sse4" && Name != "sse4.2" && Name != "sse4.1")) + return false; + + if (Enabled) { + if (Name == "mmx") + Features["mmx"] = true; + else if (Name == "sse") + Features["mmx"] = Features["sse"] = true; + else if (Name == "sse2") + Features["mmx"] = Features["sse"] = Features["sse2"] = true; + else if (Name == "sse3") + Features["mmx"] = Features["sse"] = Features["sse2"] = + Features["sse3"] = true; + else if (Name == "ssse3") + Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["ssse3"] = true; + else if (Name == "sse4" || Name == "sse4.2") + Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["ssse3"] = Features["sse41"] = Features["sse42"] = true; + else if (Name == "sse4.1") + Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["ssse3"] = Features["sse41"] = true; + else if (Name == "3dnow") + Features["3dnowa"] = true; + else if (Name == "3dnowa") + Features["3dnow"] = Features["3dnowa"] = true; + else if (Name == "aes") + Features["aes"] = true; + } else { + if (Name == "mmx") + Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; + else if (Name == "sse") + Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; + else if (Name == "sse2") + Features["sse2"] = Features["sse3"] = Features["ssse3"] = + Features["sse41"] = Features["sse42"] = false; + else if (Name == "sse3") + Features["sse3"] = Features["ssse3"] = Features["sse41"] = + Features["sse42"] = false; + else if (Name == "ssse3") + Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; + else if (Name == "sse4") + Features["sse41"] = Features["sse42"] = false; + else if (Name == "sse4.2") + Features["sse42"] = false; + else if (Name == "sse4.1") + Features["sse41"] = Features["sse42"] = false; + else if (Name == "3dnow") + Features["3dnow"] = Features["3dnowa"] = false; + else if (Name == "3dnowa") + Features["3dnowa"] = false; + else if (Name == "aes") + Features["aes"] = false; + } + + return true; +} + +/// HandleTargetOptions - Perform initialization based on the user +/// configured set of features. +void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) { + // Remember the maximum enabled sselevel. + for (unsigned i = 0, e = Features.size(); i !=e; ++i) { + // Ignore disabled features. + if (Features[i][0] == '-') + continue; + + if (Features[i].substr(1) == "aes") { + HasAES = true; + continue; + } + + assert(Features[i][0] == '+' && "Invalid target feature!"); + X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Features[i].substr(1)) + .Case("sse42", SSE42) + .Case("sse41", SSE41) + .Case("ssse3", SSSE3) + .Case("sse3", SSE3) + .Case("sse2", SSE2) + .Case("sse", SSE1) + .Case("mmx", MMX) + .Default(NoMMXSSE); + SSELevel = std::max(SSELevel, Level); + + AMD3DNowEnum ThreeDNowLevel = + llvm::StringSwitch<AMD3DNowEnum>(Features[i].substr(1)) + .Case("3dnowa", AMD3DNowAthlon) + .Case("3dnow", AMD3DNow) + .Default(NoAMD3DNow); + + AMD3DNowLevel = std::max(AMD3DNowLevel, ThreeDNowLevel); + } +} + +/// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines +/// that are not tied to a specific subtarget. +void X86TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Target identification. + if (PointerWidth == 64) { + Builder.defineMacro("_LP64"); + Builder.defineMacro("__LP64__"); + Builder.defineMacro("__amd64__"); + Builder.defineMacro("__amd64"); + Builder.defineMacro("__x86_64"); + Builder.defineMacro("__x86_64__"); + } else { + DefineStd(Builder, "i386", Opts); + } + + if (HasAES) + Builder.defineMacro("__AES__"); + + // Target properties. + Builder.defineMacro("__LITTLE_ENDIAN__"); + + // Subtarget options. + Builder.defineMacro("__nocona"); + Builder.defineMacro("__nocona__"); + Builder.defineMacro("__tune_nocona__"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline + // functions in glibc header files that use FP Stack inline asm which the + // backend can't deal with (PR879). + Builder.defineMacro("__NO_MATH_INLINES"); + + // Each case falls through to the previous one here. + switch (SSELevel) { + case SSE42: + Builder.defineMacro("__SSE4_2__"); + case SSE41: + Builder.defineMacro("__SSE4_1__"); + case SSSE3: + Builder.defineMacro("__SSSE3__"); + case SSE3: + Builder.defineMacro("__SSE3__"); + case SSE2: + Builder.defineMacro("__SSE2__"); + Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied. + case SSE1: + Builder.defineMacro("__SSE__"); + Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied. + case MMX: + Builder.defineMacro("__MMX__"); + case NoMMXSSE: + break; + } + + // Each case falls through to the previous one here. + switch (AMD3DNowLevel) { + case AMD3DNowAthlon: + Builder.defineMacro("__3dNOW_A__"); + case AMD3DNow: + Builder.defineMacro("__3dNOW__"); + case NoAMD3DNow: + break; + } +} + + +bool +X86TargetInfo::validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + 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': // Any register accessible as [r]l: a, b, c, and d. + case 'y': // Any MMX register. + case 'x': // Any SSE register. + case 'Q': // Any register accessible as [r]h: a, b, c, and d. + case 'e': // 32-bit signed integer constant for use with zero-extending + // x86_64 instructions. + case 'Z': // 32-bit unsigned integer constant for use with zero-extending + // x86_64 instructions. + case 'N': // unsigned 8-bit integer constant for use with in and out + // instructions. + case 'R': // "legacy" registers: ax, bx, cx, dx, di, si, sp, bp. + Info.setAllowsRegister(); + return true; + } +} + +std::string +X86TargetInfo::convertConstraint(const char Constraint) const { + 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); + } +} +} // end anonymous namespace + +namespace { +// X86-32 generic target +class X86_32TargetInfo : public X86TargetInfo { +public: + X86_32TargetInfo(const std::string& triple) : X86TargetInfo(triple) { + DoubleAlign = LongLongAlign = 32; + LongDoubleWidth = 96; + LongDoubleAlign = 32; + DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-" + "a0:0:64-f80:32:32-n8:16:32"; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + RegParmMax = 3; + } + virtual const char *getVAListDeclaration() const { + return "typedef char* __builtin_va_list;"; + } + + int getEHDataRegisterNumber(unsigned RegNo) const { + if (RegNo == 0) return 0; + if (RegNo == 1) return 2; + return -1; + } +}; +} // end anonymous namespace + +namespace { +class OpenBSDI386TargetInfo : public OpenBSDTargetInfo<X86_32TargetInfo> { +public: + OpenBSDI386TargetInfo(const std::string& triple) : + OpenBSDTargetInfo<X86_32TargetInfo>(triple) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } +}; +} // end anonymous namespace + +namespace { +class DarwinI386TargetInfo : public DarwinTargetInfo<X86_32TargetInfo> { +public: + DarwinI386TargetInfo(const std::string& triple) : + DarwinTargetInfo<X86_32TargetInfo>(triple) { + LongDoubleWidth = 128; + LongDoubleAlign = 128; + SizeType = UnsignedLong; + IntPtrType = SignedLong; + DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-" + "a0:0:64-f80:128:128-n8:16:32"; + HasAlignMac68kSupport = true; + } + +}; +} // end anonymous namespace + +namespace { +// x86-32 Windows target +class WindowsX86_32TargetInfo : public X86_32TargetInfo { +public: + WindowsX86_32TargetInfo(const std::string& triple) + : X86_32TargetInfo(triple) { + TLSSupported = false; + WCharType = UnsignedShort; + DoubleAlign = LongLongAlign = 64; + DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-" + "v128:128:128-a0:0:64-f80:32:32-n8:16:32"; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + // This list is based off of the the list of things MingW defines + Builder.defineMacro("_WIN32"); + DefineStd(Builder, "WIN32", Opts); + DefineStd(Builder, "WINNT", Opts); + Builder.defineMacro("_X86_"); + } +}; +} // end anonymous namespace + +namespace { + +// x86-32 Windows Visual Studio target +class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo { +public: + VisualStudioWindowsX86_32TargetInfo(const std::string& triple) + : WindowsX86_32TargetInfo(triple) { + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); + // The value of the following reflects processor type. + // 300=386, 400=486, 500=Pentium, 600=Blend (default) + // We lost the original triple, so we use the default. + Builder.defineMacro("_M_IX86", "600"); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 MinGW target +class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo { +public: + MinGWX86_32TargetInfo(const std::string& triple) + : WindowsX86_32TargetInfo(triple) { + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__MSVCRT__"); + Builder.defineMacro("__MINGW32__"); + Builder.defineMacro("__declspec", "__declspec"); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 Cygwin target +class CygwinX86_32TargetInfo : public X86_32TargetInfo { +public: + CygwinX86_32TargetInfo(const std::string& triple) + : X86_32TargetInfo(triple) { + TLSSupported = false; + WCharType = UnsignedShort; + DoubleAlign = LongLongAlign = 64; + DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" + "a0:0:64-f80:32:32-n8:16:32"; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__CYGWIN__"); + Builder.defineMacro("__CYGWIN32__"); + DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 Haiku target +class HaikuX86_32TargetInfo : public X86_32TargetInfo { +public: + HaikuX86_32TargetInfo(const std::string& triple) + : X86_32TargetInfo(triple) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__INTEL__"); + Builder.defineMacro("__HAIKU__"); + } +}; +} // end anonymous namespace + +namespace { +// x86-64 generic target +class X86_64TargetInfo : public X86TargetInfo { +public: + X86_64TargetInfo(const std::string &triple) : X86TargetInfo(triple) { + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + LongDoubleWidth = 128; + LongDoubleAlign = 128; + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + Int64Type = SignedLong; + RegParmMax = 6; + + DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" + "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"; + } + virtual const char *getVAListDeclaration() const { + return "typedef struct __va_list_tag {" + " unsigned gp_offset;" + " unsigned fp_offset;" + " void* overflow_arg_area;" + " void* reg_save_area;" + "} __va_list_tag;" + "typedef __va_list_tag __builtin_va_list[1];"; + } + + int getEHDataRegisterNumber(unsigned RegNo) const { + if (RegNo == 0) return 0; + if (RegNo == 1) return 1; + return -1; + } +}; +} // end anonymous namespace + +namespace { +// x86-64 Windows target +class WindowsX86_64TargetInfo : public X86_64TargetInfo { +public: + WindowsX86_64TargetInfo(const std::string& triple) + : X86_64TargetInfo(triple) { + TLSSupported = false; + WCharType = UnsignedShort; + LongWidth = LongAlign = 32; + DoubleAlign = LongLongAlign = 64; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + X86_64TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_WIN64"); + DefineStd(Builder, "WIN64", Opts); + } +}; +} // end anonymous namespace + +namespace { +// x86-64 Windows Visual Studio target +class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo { +public: + VisualStudioWindowsX86_64TargetInfo(const std::string& triple) + : WindowsX86_64TargetInfo(triple) { + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_M_X64"); + } + virtual const char *getVAListDeclaration() const { + return "typedef char* va_list;"; + } +}; +} // end anonymous namespace + +namespace { +// x86-64 MinGW target +class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo { +public: + MinGWX86_64TargetInfo(const std::string& triple) + : WindowsX86_64TargetInfo(triple) { + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__MSVCRT__"); + Builder.defineMacro("__MINGW64__"); + Builder.defineMacro("__declspec"); + } +}; +} // end anonymous namespace + +namespace { +class DarwinX86_64TargetInfo : public DarwinTargetInfo<X86_64TargetInfo> { +public: + DarwinX86_64TargetInfo(const std::string& triple) + : DarwinTargetInfo<X86_64TargetInfo>(triple) { + Int64Type = SignedLongLong; + } +}; +} // end anonymous namespace + +namespace { +class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo<X86_64TargetInfo> { +public: + OpenBSDX86_64TargetInfo(const std::string& triple) + : OpenBSDTargetInfo<X86_64TargetInfo>(triple) { + IntMaxType = SignedLongLong; + UIntMaxType = UnsignedLongLong; + Int64Type = SignedLongLong; + } +}; +} // end anonymous namespace + +namespace { +class ARMTargetInfo : public TargetInfo { + // Possible FPU choices. + enum FPUMode { + NoFPU, + VFP2FPU, + VFP3FPU, + NeonFPU + }; + + static bool FPUModeIsVFP(FPUMode Mode) { + return Mode >= VFP2FPU && Mode <= NeonFPU; + } + + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char * const GCCRegNames[]; + + std::string ABI, CPU; + + unsigned FPU : 3; + + unsigned IsThumb : 1; + + // Initialized via features. + unsigned SoftFloat : 1; + unsigned SoftFloatABI : 1; + + static const Builtin::Info BuiltinInfo[]; + +public: + ARMTargetInfo(const std::string &TripleStr) + : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s") + { + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + + // {} in inline assembly are neon specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + + // FIXME: Should we just treat this as a feature? + IsThumb = getTriple().getArchName().startswith("thumb"); + if (IsThumb) { + DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-" + "v64:64:64-v128:128:128-a0:0:32-n32"); + } else { + DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-" + "v64:64:64-v128:128:128-a0:0:64-n32"); + } + } + virtual const char *getABI() const { return ABI.c_str(); } + virtual bool setABI(const std::string &Name) { + ABI = Name; + + // The defaults (above) are for AAPCS, check if we need to change them. + // + // FIXME: We need support for -meabi... we could just mangle it into the + // name. + if (Name == "apcs-gnu") { + DoubleAlign = LongLongAlign = LongDoubleAlign = 32; + SizeType = UnsignedLong; + + // Do not respect the alignment of bit-field types when laying out + // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc. + UseBitFieldTypeAlignment = false; + + if (IsThumb) { + DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" + "i64:32:32-f32:32:32-f64:32:32-" + "v64:64:64-v128:128:128-a0:0:32-n32"); + } else { + DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:32:32-f32:32:32-f64:32:32-" + "v64:64:64-v128:128:128-a0:0:64-n32"); + } + + // FIXME: Override "preferred align" for double and long long. + } else if (Name == "aapcs") { + // FIXME: Enumerated types are variable width in straight AAPCS. + } else if (Name == "aapcs-linux") { + ; + } else + return false; + + return true; + } + + void getDefaultFeatures(const std::string &CPU, + llvm::StringMap<bool> &Features) const { + // FIXME: This should not be here. + Features["vfp2"] = false; + Features["vfp3"] = false; + Features["neon"] = false; + + if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore") + Features["vfp2"] = true; + else if (CPU == "cortex-a8" || CPU == "cortex-a9") + Features["neon"] = true; + } + + virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, + const std::string &Name, + bool Enabled) const { + if (Name == "soft-float" || Name == "soft-float-abi") { + Features[Name] = Enabled; + } else if (Name == "vfp2" || Name == "vfp3" || Name == "neon") { + // These effectively are a single option, reset them when any is enabled. + if (Enabled) + Features["vfp2"] = Features["vfp3"] = Features["neon"] = false; + Features[Name] = Enabled; + } else + return false; + + return true; + } + + virtual void HandleTargetFeatures(std::vector<std::string> &Features) { + FPU = NoFPU; + SoftFloat = SoftFloatABI = false; + for (unsigned i = 0, e = Features.size(); i != e; ++i) { + if (Features[i] == "+soft-float") + SoftFloat = true; + else if (Features[i] == "+soft-float-abi") + SoftFloatABI = true; + else if (Features[i] == "+vfp2") + FPU = VFP2FPU; + else if (Features[i] == "+vfp3") + FPU = VFP3FPU; + else if (Features[i] == "+neon") + FPU = NeonFPU; + } + + // Remove front-end specific options which the backend handles differently. + std::vector<std::string>::iterator it; + it = std::find(Features.begin(), Features.end(), "+soft-float"); + if (it != Features.end()) + Features.erase(it); + it = std::find(Features.begin(), Features.end(), "+soft-float-abi"); + if (it != Features.end()) + Features.erase(it); + } + + static const char *getCPUDefineSuffix(llvm::StringRef Name) { + return llvm::StringSwitch<const char*>(Name) + .Cases("arm8", "arm810", "4") + .Cases("strongarm", "strongarm110", "strongarm1100", "strongarm1110", "4") + .Cases("arm7tdmi", "arm7tdmi-s", "arm710t", "arm720t", "arm9", "4T") + .Cases("arm9tdmi", "arm920", "arm920t", "arm922t", "arm940t", "4T") + .Case("ep9312", "4T") + .Cases("arm10tdmi", "arm1020t", "5T") + .Cases("arm9e", "arm946e-s", "arm966e-s", "arm968e-s", "5TE") + .Case("arm926ej-s", "5TEJ") + .Cases("arm10e", "arm1020e", "arm1022e", "5TE") + .Cases("xscale", "iwmmxt", "5TE") + .Case("arm1136j-s", "6J") + .Cases("arm1176jz-s", "arm1176jzf-s", "6ZK") + .Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K") + .Cases("arm1156t2-s", "arm1156t2f-s", "6T2") + .Cases("cortex-a8", "cortex-a9", "7A") + .Default(0); + } + virtual bool setCPU(const std::string &Name) { + if (!getCPUDefineSuffix(Name)) + return false; + + CPU = Name; + return true; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Target identification. + Builder.defineMacro("__arm"); + Builder.defineMacro("__arm__"); + + // Target properties. + Builder.defineMacro("__ARMEL__"); + Builder.defineMacro("__LITTLE_ENDIAN__"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + llvm::StringRef CPUArch = getCPUDefineSuffix(CPU); + Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__"); + + // Subtarget options. + + // FIXME: It's more complicated than this and we don't really support + // interworking. + if ('5' <= CPUArch[0] && CPUArch[0] <= '7') + Builder.defineMacro("__THUMB_INTERWORK__"); + + if (ABI == "aapcs" || ABI == "aapcs-linux") + Builder.defineMacro("__ARM_EABI__"); + + if (SoftFloat) + Builder.defineMacro("__SOFTFP__"); + + if (CPU == "xscale") + Builder.defineMacro("__XSCALE__"); + + bool IsThumb2 = IsThumb && (CPUArch == "6T2" || CPUArch.startswith("7")); + if (IsThumb) { + Builder.defineMacro("__THUMBEL__"); + Builder.defineMacro("__thumb__"); + if (IsThumb2) + Builder.defineMacro("__thumb2__"); + } + + // Note, this is always on in gcc, even though it doesn't make sense. + Builder.defineMacro("__APCS_32__"); + + if (FPUModeIsVFP((FPUMode) FPU)) + Builder.defineMacro("__VFP_FP__"); + + // This only gets set when Neon instructions are actually available, unlike + // the VFP define, hence the soft float and arch check. This is subtly + // different from gcc, we follow the intent which was that it should be set + // when Neon instructions are actually available. + if (FPU == NeonFPU && !SoftFloat && IsThumb2) + Builder.defineMacro("__ARM_NEON__"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + Records = BuiltinInfo; + NumRecords = clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + virtual const char *getVAListDeclaration() const { + return "typedef char* __builtin_va_list;"; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const; + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + // FIXME: Check if this is complete + switch (*Name) { + default: + case 'l': // r0-r7 + case 'h': // r8-r15 + case 'w': // VFP Floating point register single precision + case 'P': // VFP Floating point register double precision + Info.setAllowsRegister(); + return true; + } + return false; + } + virtual const char *getClobbers() const { + // FIXME: Is this really right? + return ""; + } +}; + +const char * const ARMTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; + +void ARMTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} + +const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { + + { { "a1" }, "r0" }, + { { "a2" }, "r1" }, + { { "a3" }, "r2" }, + { { "a4" }, "r3" }, + { { "v1" }, "r4" }, + { { "v2" }, "r5" }, + { { "v3" }, "r6" }, + { { "v4" }, "r7" }, + { { "v5" }, "r8" }, + { { "v6", "rfp" }, "r9" }, + { { "sl" }, "r10" }, + { { "fp" }, "r11" }, + { { "ip" }, "r12" }, + { { "sp" }, "r13" }, + { { "lr" }, "r14" }, + { { "pc" }, "r15" }, +}; + +void ARMTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} + +const Builtin::Info ARMTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false }, +#include "clang/Basic/BuiltinsARM.def" +}; +} // end anonymous namespace. + + +namespace { +class DarwinARMTargetInfo : + public DarwinTargetInfo<ARMTargetInfo> { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + getDarwinDefines(Builder, Opts, Triple); + } + +public: + DarwinARMTargetInfo(const std::string& triple) + : DarwinTargetInfo<ARMTargetInfo>(triple) { + HasAlignMac68kSupport = true; + } +}; +} // end anonymous namespace. + +namespace { +class SparcV8TargetInfo : public TargetInfo { + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char * const GCCRegNames[]; +public: + SparcV8TargetInfo(const std::string& triple) : TargetInfo(triple) { + // FIXME: Support Sparc quad-precision long double? + DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32"; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "sparc", Opts); + Builder.defineMacro("__sparcv8"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement! + } + virtual const char *getVAListDeclaration() const { + return "typedef void* __builtin_va_list;"; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const; + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const { + // FIXME: Implement! + return false; + } + virtual const char *getClobbers() const { + // FIXME: Implement! + return ""; + } +}; + +const char * const SparcV8TargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" +}; + +void SparcV8TargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} + +const TargetInfo::GCCRegAlias SparcV8TargetInfo::GCCRegAliases[] = { + { { "g0" }, "r0" }, + { { "g1" }, "r1" }, + { { "g2" }, "r2" }, + { { "g3" }, "r3" }, + { { "g4" }, "r4" }, + { { "g5" }, "r5" }, + { { "g6" }, "r6" }, + { { "g7" }, "r7" }, + { { "o0" }, "r8" }, + { { "o1" }, "r9" }, + { { "o2" }, "r10" }, + { { "o3" }, "r11" }, + { { "o4" }, "r12" }, + { { "o5" }, "r13" }, + { { "o6", "sp" }, "r14" }, + { { "o7" }, "r15" }, + { { "l0" }, "r16" }, + { { "l1" }, "r17" }, + { { "l2" }, "r18" }, + { { "l3" }, "r19" }, + { { "l4" }, "r20" }, + { { "l5" }, "r21" }, + { { "l6" }, "r22" }, + { { "l7" }, "r23" }, + { { "i0" }, "r24" }, + { { "i1" }, "r25" }, + { { "i2" }, "r26" }, + { { "i3" }, "r27" }, + { { "i4" }, "r28" }, + { { "i5" }, "r29" }, + { { "i6", "fp" }, "r30" }, + { { "i7" }, "r31" }, +}; + +void SparcV8TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} +} // end anonymous namespace. + +namespace { +class AuroraUXSparcV8TargetInfo : public AuroraUXTargetInfo<SparcV8TargetInfo> { +public: + AuroraUXSparcV8TargetInfo(const std::string& triple) : + AuroraUXTargetInfo<SparcV8TargetInfo>(triple) { + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + } +}; +class SolarisSparcV8TargetInfo : public SolarisTargetInfo<SparcV8TargetInfo> { +public: + SolarisSparcV8TargetInfo(const std::string& triple) : + SolarisTargetInfo<SparcV8TargetInfo>(triple) { + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + } +}; +} // end anonymous namespace. + +namespace { + class PIC16TargetInfo : public TargetInfo{ + public: + PIC16TargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = false; + IntWidth = 16; + LongWidth = LongLongWidth = 32; + PointerWidth = 16; + IntAlign = 8; + LongAlign = LongLongAlign = 8; + PointerAlign = 8; + SizeType = UnsignedInt; + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + IntPtrType = SignedShort; + PtrDiffType = SignedInt; + SigAtomicType = SignedLong; + FloatWidth = 32; + FloatAlign = 32; + DoubleWidth = 32; + DoubleAlign = 32; + LongDoubleWidth = 32; + LongDoubleAlign = 32; + FloatFormat = &llvm::APFloat::IEEEsingle; + DoubleFormat = &llvm::APFloat::IEEEsingle; + LongDoubleFormat = &llvm::APFloat::IEEEsingle; + DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-f32:32:32-n8"; + + } + virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return 16; } + virtual uint64_t getPointerAlignV(unsigned AddrSpace) const { return 8; } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__pic16"); + Builder.defineMacro("__PIC16"); + Builder.defineMacro("rom", "__attribute__((address_space(1)))"); + Builder.defineMacro("ram", "__attribute__((address_space(0)))"); + Builder.defineMacro("__section(SectName)", + "__attribute__((section(SectName)))"); + Builder.defineMacro("near", + "__attribute__((section(\"Address=NEAR\")))"); + Builder.defineMacro("__address(Addr)", + "__attribute__((section(\"Address=\"#Addr)))"); + Builder.defineMacro("__config(conf)", "asm(\"CONFIG \"#conf)"); + Builder.defineMacro("__idlocs(value)", "asm(\"__IDLOCS \"#value)"); + Builder.defineMacro("interrupt", + "__attribute__((section(\"interrupt=0x4\"))) \ + __attribute__((used))"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const {} + virtual const char *getVAListDeclaration() const { + return "typedef char* __builtin_va_list;"; + } + virtual const char *getClobbers() const { + return ""; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const {} + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const { + return true; + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const {} + virtual bool useGlobalsForAutomaticVariables() const {return true;} + }; +} + +namespace { + class MSP430TargetInfo : public TargetInfo { + static const char * const GCCRegNames[]; + public: + MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = false; + IntWidth = 16; IntAlign = 16; + LongWidth = 32; LongLongWidth = 64; + LongAlign = LongLongAlign = 16; + PointerWidth = 16; PointerAlign = 16; + SizeType = UnsignedInt; + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + IntPtrType = SignedShort; + PtrDiffType = SignedInt; + SigAtomicType = SignedLong; + DescriptionString = "e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32-n8:16"; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("MSP430"); + Builder.defineMacro("__MSP430__"); + // FIXME: defines for different 'flavours' of MCU + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement. + Records = 0; + NumRecords = 0; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + // No aliases. + Aliases = 0; + NumAliases = 0; + } + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const { + // No target constraints for now. + return false; + } + virtual const char *getClobbers() const { + // FIXME: Is this really right? + return ""; + } + virtual const char *getVAListDeclaration() const { + // FIXME: implement + return "typedef char* __builtin_va_list;"; + } + }; + + const char * const MSP430TargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" + }; + + void MSP430TargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } +} + + +namespace { + class SystemZTargetInfo : public TargetInfo { + static const char * const GCCRegNames[]; + public: + SystemZTargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = false; + IntWidth = IntAlign = 32; + LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; + PointerWidth = PointerAlign = 64; + DescriptionString = "E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16-n32:64"; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__s390__"); + Builder.defineMacro("__s390x__"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement. + Records = 0; + NumRecords = 0; + } + + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + // No aliases. + Aliases = 0; + NumAliases = 0; + } + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const { + // FIXME: implement + return true; + } + virtual const char *getClobbers() const { + // FIXME: Is this really right? + return ""; + } + virtual const char *getVAListDeclaration() const { + // FIXME: implement + return "typedef char* __builtin_va_list;"; + } + }; + + const char * const SystemZTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" + }; + + void SystemZTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } +} + +namespace { + class BlackfinTargetInfo : public TargetInfo { + static const char * const GCCRegNames[]; + public: + BlackfinTargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = false; + DoubleAlign = 32; + LongLongAlign = 32; + LongDoubleAlign = 32; + DescriptionString = "e-p:32:32-i64:32-f64:32-n32"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "bfin", Opts); + DefineStd(Builder, "BFIN", Opts); + Builder.defineMacro("__ADSPBLACKFIN__"); + // FIXME: This one is really dependent on -mcpu + Builder.defineMacro("__ADSPLPBLACKFIN__"); + // FIXME: Add cpu-dependent defines and __SILICON_REVISION__ + } + + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement. + Records = 0; + NumRecords = 0; + } + + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + // No aliases. + Aliases = 0; + NumAliases = 0; + } + + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + if (strchr("adzDWeABbvfcCtukxywZY", Name[0])) { + Info.setAllowsRegister(); + return true; + } + return false; + } + + virtual const char *getClobbers() const { + return ""; + } + + virtual const char *getVAListDeclaration() const { + return "typedef char* __builtin_va_list;"; + } + }; + + const char * const BlackfinTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "p0", "p1", "p2", "p3", "p4", "p5", "sp", "fp", + "i0", "i1", "i2", "i3", "b0", "b1", "b2", "b3", + "l0", "l1", "l2", "l3", "m0", "m1", "m2", "m3", + "a0", "a1", "cc", + "rets", "reti", "retx", "retn", "rete", "astat", "seqstat", "usp", + "argp", "lt0", "lt1", "lc0", "lc1", "lb0", "lb1" + }; + + void BlackfinTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } +} + +namespace { + + // LLVM and Clang cannot be used directly to output native binaries for + // target, but is used to compile C code to llvm bitcode with correct + // type and alignment information. + // + // TCE uses the llvm bitcode as input and uses it for generating customized + // target processor and program binary. TCE co-design environment is + // publicly available in http://tce.cs.tut.fi + + class TCETargetInfo : public TargetInfo{ + public: + TCETargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = false; + IntWidth = 32; + LongWidth = LongLongWidth = 32; + PointerWidth = 32; + IntAlign = 32; + LongAlign = LongLongAlign = 32; + PointerAlign = 32; + SizeType = UnsignedInt; + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + IntPtrType = SignedInt; + PtrDiffType = SignedInt; + FloatWidth = 32; + FloatAlign = 32; + DoubleWidth = 32; + DoubleAlign = 32; + LongDoubleWidth = 32; + LongDoubleAlign = 32; + FloatFormat = &llvm::APFloat::IEEEsingle; + DoubleFormat = &llvm::APFloat::IEEEsingle; + LongDoubleFormat = &llvm::APFloat::IEEEsingle; + DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-" + "i16:16:32-i32:32:32-i64:32:32-" + "f32:32:32-f64:64:64-v64:64:64-" + "v128:128:128-a0:0:64-n32"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "tce", Opts); + Builder.defineMacro("__TCE__"); + Builder.defineMacro("__TCE_V1__"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const {} + virtual const char *getClobbers() const { + return ""; + } + virtual const char *getVAListDeclaration() const { + return "typedef void* __builtin_va_list;"; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const {} + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const { + return true; + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const {} + }; +} + +namespace { +class MipsTargetInfo : public TargetInfo { + std::string ABI, CPU; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char * const GCCRegNames[]; +public: + MipsTargetInfo(const std::string& triple) : TargetInfo(triple), ABI("o32") { + DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" + "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32"; + } + virtual const char *getABI() const { return ABI.c_str(); } + virtual bool setABI(const std::string &Name) { + + if ((Name == "o32") || (Name == "eabi")) { + ABI = Name; + return true; + } else + return false; + } + virtual bool setCPU(const std::string &Name) { + CPU = Name; + return true; + } + void getDefaultFeatures(const std::string &CPU, + llvm::StringMap<bool> &Features) const { + Features[ABI] = true; + Features[CPU] = true; + } + virtual void getArchDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + if (ABI == "o32") + Builder.defineMacro("__mips_o32"); + else if (ABI == "eabi") + Builder.defineMacro("__mips_eabi"); + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "mips", Opts); + Builder.defineMacro("_mips"); + DefineStd(Builder, "MIPSEB", Opts); + Builder.defineMacro("_MIPSEB"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + getArchDefines(Opts, Builder); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement! + } + virtual const char *getVAListDeclaration() const { + return "typedef void* __builtin_va_list;"; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const; + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + case 'r': // CPU registers. + case 'd': // Equivalent to "r" unless generating MIPS16 code. + case 'y': // Equivalent to "r", backwards compatibility only. + case 'f': // floating-point registers. + Info.setAllowsRegister(); + return true; + } + return false; + } + + virtual const char *getClobbers() const { + // FIXME: Implement! + return ""; + } +}; + +const char * const MipsTargetInfo::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", "$sp", "$fp", "$31", + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", + "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", + "$fcc5","$fcc6","$fcc7" +}; + +void MipsTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} + +const TargetInfo::GCCRegAlias MipsTargetInfo::GCCRegAliases[] = { + { { "at" }, "$1" }, + { { "v0" }, "$2" }, + { { "v1" }, "$3" }, + { { "a0" }, "$4" }, + { { "a1" }, "$5" }, + { { "a2" }, "$6" }, + { { "a3" }, "$7" }, + { { "t0" }, "$8" }, + { { "t1" }, "$9" }, + { { "t2" }, "$10" }, + { { "t3" }, "$11" }, + { { "t4" }, "$12" }, + { { "t5" }, "$13" }, + { { "t6" }, "$14" }, + { { "t7" }, "$15" }, + { { "s0" }, "$16" }, + { { "s1" }, "$17" }, + { { "s2" }, "$18" }, + { { "s3" }, "$19" }, + { { "s4" }, "$20" }, + { { "s5" }, "$21" }, + { { "s6" }, "$22" }, + { { "s7" }, "$23" }, + { { "t8" }, "$24" }, + { { "t9" }, "$25" }, + { { "k0" }, "$26" }, + { { "k1" }, "$27" }, + { { "gp" }, "$28" }, + { { "sp" }, "$29" }, + { { "fp" }, "$30" }, + { { "ra" }, "$31" } +}; + +void MipsTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} +} // end anonymous namespace. + +namespace { +class MipselTargetInfo : public MipsTargetInfo { +public: + MipselTargetInfo(const std::string& triple) : MipsTargetInfo(triple) { + DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-" + "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const; +}; + +void MipselTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "mips", Opts); + Builder.defineMacro("_mips"); + DefineStd(Builder, "MIPSEL", Opts); + Builder.defineMacro("_MIPSEL"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + getArchDefines(Opts, Builder); +} +} // end anonymous namespace. + +//===----------------------------------------------------------------------===// +// Driver code +//===----------------------------------------------------------------------===// + +static TargetInfo *AllocateTarget(const std::string &T) { + llvm::Triple Triple(T); + llvm::Triple::OSType os = Triple.getOS(); + + switch (Triple.getArch()) { + default: + return NULL; + + case llvm::Triple::arm: + case llvm::Triple::thumb: + switch (os) { + case llvm::Triple::Darwin: + return new DarwinARMTargetInfo(T); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<ARMTargetInfo>(T); + default: + return new ARMTargetInfo(T); + } + + case llvm::Triple::bfin: + return new BlackfinTargetInfo(T); + + case llvm::Triple::msp430: + return new MSP430TargetInfo(T); + + case llvm::Triple::mips: + if (os == llvm::Triple::Psp) + return new PSPTargetInfo<MipsTargetInfo>(T); + if (os == llvm::Triple::Linux) + return new LinuxTargetInfo<MipsTargetInfo>(T); + return new MipsTargetInfo(T); + + case llvm::Triple::mipsel: + if (os == llvm::Triple::Psp) + return new PSPTargetInfo<MipselTargetInfo>(T); + if (os == llvm::Triple::Linux) + return new LinuxTargetInfo<MipselTargetInfo>(T); + return new MipselTargetInfo(T); + + case llvm::Triple::pic16: + return new PIC16TargetInfo(T); + + case llvm::Triple::ppc: + if (os == llvm::Triple::Darwin) + return new DarwinTargetInfo<PPCTargetInfo>(T); + else if (os == llvm::Triple::FreeBSD) + return new FreeBSDTargetInfo<PPC32TargetInfo>(T); + return new PPC32TargetInfo(T); + + case llvm::Triple::ppc64: + if (os == llvm::Triple::Darwin) + return new DarwinTargetInfo<PPC64TargetInfo>(T); + else if (os == llvm::Triple::Lv2) + return new PS3PPUTargetInfo<PPC64TargetInfo>(T); + else if (os == llvm::Triple::FreeBSD) + return new FreeBSDTargetInfo<PPC64TargetInfo>(T); + return new PPC64TargetInfo(T); + + case llvm::Triple::mblaze: + return new MBlazeTargetInfo(T); + + case llvm::Triple::sparc: + if (os == llvm::Triple::AuroraUX) + return new AuroraUXSparcV8TargetInfo(T); + if (os == llvm::Triple::Solaris) + return new SolarisSparcV8TargetInfo(T); + return new SparcV8TargetInfo(T); + + // FIXME: Need a real SPU target. + case llvm::Triple::cellspu: + return new PS3SPUTargetInfo<PPC64TargetInfo>(T); + + case llvm::Triple::systemz: + return new SystemZTargetInfo(T); + + case llvm::Triple::tce: + return new TCETargetInfo(T); + + case llvm::Triple::x86: + switch (os) { + case llvm::Triple::AuroraUX: + return new AuroraUXTargetInfo<X86_32TargetInfo>(T); + case llvm::Triple::Darwin: + return new DarwinI386TargetInfo(T); + case llvm::Triple::Linux: + return new LinuxTargetInfo<X86_32TargetInfo>(T); + case llvm::Triple::DragonFly: + return new DragonFlyBSDTargetInfo<X86_32TargetInfo>(T); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<X86_32TargetInfo>(T); + case llvm::Triple::OpenBSD: + return new OpenBSDI386TargetInfo(T); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<X86_32TargetInfo>(T); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<X86_32TargetInfo>(T); + case llvm::Triple::Cygwin: + return new CygwinX86_32TargetInfo(T); + case llvm::Triple::MinGW32: + return new MinGWX86_32TargetInfo(T); + case llvm::Triple::Win32: + return new VisualStudioWindowsX86_32TargetInfo(T); + case llvm::Triple::Haiku: + return new HaikuX86_32TargetInfo(T); + default: + return new X86_32TargetInfo(T); + } + + case llvm::Triple::x86_64: + switch (os) { + case llvm::Triple::AuroraUX: + return new AuroraUXTargetInfo<X86_64TargetInfo>(T); + case llvm::Triple::Darwin: + return new DarwinX86_64TargetInfo(T); + case llvm::Triple::Linux: + return new LinuxTargetInfo<X86_64TargetInfo>(T); + case llvm::Triple::DragonFly: + return new DragonFlyBSDTargetInfo<X86_64TargetInfo>(T); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<X86_64TargetInfo>(T); + case llvm::Triple::OpenBSD: + return new OpenBSDX86_64TargetInfo(T); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<X86_64TargetInfo>(T); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<X86_64TargetInfo>(T); + case llvm::Triple::MinGW64: + return new MinGWX86_64TargetInfo(T); + case llvm::Triple::Win32: // This is what Triple.h supports now. + return new VisualStudioWindowsX86_64TargetInfo(T); + default: + return new X86_64TargetInfo(T); + } + } +} + +/// CreateTargetInfo - Return the target info object for the specified target +/// triple. +TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags, + TargetOptions &Opts) { + llvm::Triple Triple(Opts.Triple); + + // Construct the target + llvm::OwningPtr<TargetInfo> Target(AllocateTarget(Triple.str())); + if (!Target) { + Diags.Report(diag::err_target_unknown_triple) << Triple.str(); + return 0; + } + + // Set the target CPU if specified. + if (!Opts.CPU.empty() && !Target->setCPU(Opts.CPU)) { + Diags.Report(diag::err_target_unknown_cpu) << Opts.CPU; + return 0; + } + + // Set the target ABI if specified. + if (!Opts.ABI.empty() && !Target->setABI(Opts.ABI)) { + Diags.Report(diag::err_target_unknown_abi) << Opts.ABI; + return 0; + } + + // Compute the default target features, we need the target to handle this + // because features may have dependencies on one another. + llvm::StringMap<bool> Features; + Target->getDefaultFeatures(Opts.CPU, Features); + + // Apply the user specified deltas. + for (std::vector<std::string>::const_iterator it = Opts.Features.begin(), + ie = Opts.Features.end(); it != ie; ++it) { + const char *Name = it->c_str(); + + // Apply the feature via the target. + if ((Name[0] != '-' && Name[0] != '+') || + !Target->setFeatureEnabled(Features, Name + 1, (Name[0] == '+'))) { + Diags.Report(diag::err_target_invalid_feature) << Name; + return 0; + } + } + + // Add the features to the compile options. + // + // FIXME: If we are completely confident that we have the right set, we only + // need to pass the minuses. + Opts.Features.clear(); + for (llvm::StringMap<bool>::const_iterator it = Features.begin(), + ie = Features.end(); it != ie; ++it) + Opts.Features.push_back(std::string(it->second ? "+" : "-") + it->first()); + Target->HandleTargetFeatures(Opts.Features); + + return Target.take(); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/TokenKinds.cpp b/contrib/llvm/tools/clang/lib/Basic/TokenKinds.cpp new file mode 100644 index 0000000..8cdc1e3 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/TokenKinds.cpp @@ -0,0 +1,39 @@ +//===--- 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]; +} + +const char *tok::getTokenSimpleSpelling(enum TokenKind Kind) { + switch (Kind) { +#define PUNCTUATOR(X,Y) case X: return Y; +#include "clang/Basic/TokenKinds.def" + default: break; + } + + return 0; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Version.cpp b/contrib/llvm/tools/clang/lib/Basic/Version.cpp new file mode 100644 index 0000000..e0c2336 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Version.cpp @@ -0,0 +1,76 @@ +//===- Version.cpp - Clang Version Number -----------------------*- 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 several version-related utility functions for Clang. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Version.h" +#include "llvm/Support/raw_ostream.h" +#include <cstring> +#include <cstdlib> + +using namespace std; + +namespace clang { + +llvm::StringRef getClangRepositoryPath() { + static const char URL[] = "$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"; + const char *URLEnd = URL + strlen(URL); + + const char *End = strstr(URL, "/lib/Basic"); + if (End) + URLEnd = End; + + // Strip off version from a build from an integration branch. + End = strstr(URL, "/src/tools/clang"); + if (End) + URLEnd = End; + + const char *Begin = strstr(URL, "cfe/"); + if (Begin) + return llvm::StringRef(Begin + 4, URLEnd - Begin - 4); + + return llvm::StringRef(URL, URLEnd - URL); +} + +std::string getClangRevision() { +#ifdef SVN_REVISION + if (SVN_REVISION[0] != '\0') { + std::string revision; + llvm::raw_string_ostream OS(revision); + OS << strtol(SVN_REVISION, 0, 10); + return OS.str(); + } +#endif + return ""; +} + +std::string getClangFullRepositoryVersion() { + std::string buf; + llvm::raw_string_ostream OS(buf); + OS << getClangRepositoryPath(); + const std::string &Revision = getClangRevision(); + if (!Revision.empty()) + OS << ' ' << Revision; + return OS.str(); +} + +std::string getClangFullVersion() { + std::string buf; + llvm::raw_string_ostream OS(buf); +#ifdef CLANG_VENDOR + OS << CLANG_VENDOR; +#endif + OS << "clang version " CLANG_VERSION_STRING " (" + << getClangFullRepositoryVersion() << ')'; + return OS.str(); +} + +} // end namespace clang |