diff options
author | ed <ed@FreeBSD.org> | 2009-06-02 17:58:47 +0000 |
---|---|---|
committer | ed <ed@FreeBSD.org> | 2009-06-02 17:58:47 +0000 |
commit | f27e5a09a0d815b8a4814152954ff87dadfdefc0 (patch) | |
tree | ce7d964cbb5e39695b71481698f10cb099c23d4a /lib/Basic | |
download | FreeBSD-src-f27e5a09a0d815b8a4814152954ff87dadfdefc0.zip FreeBSD-src-f27e5a09a0d815b8a4814152954ff87dadfdefc0.tar.gz |
Import Clang, at r72732.
Diffstat (limited to 'lib/Basic')
-rw-r--r-- | lib/Basic/CMakeLists.txt | 24 | ||||
-rw-r--r-- | lib/Basic/ConvertUTF.c | 547 | ||||
-rw-r--r-- | lib/Basic/Diagnostic.cpp | 788 | ||||
-rw-r--r-- | lib/Basic/FileManager.cpp | 302 | ||||
-rw-r--r-- | lib/Basic/IdentifierTable.cpp | 388 | ||||
-rw-r--r-- | lib/Basic/Makefile | 22 | ||||
-rw-r--r-- | lib/Basic/SourceLocation.cpp | 125 | ||||
-rw-r--r-- | lib/Basic/SourceManager.cpp | 943 | ||||
-rw-r--r-- | lib/Basic/TargetInfo.cpp | 295 | ||||
-rw-r--r-- | lib/Basic/Targets.cpp | 1500 | ||||
-rw-r--r-- | lib/Basic/TokenKinds.cpp | 90 |
11 files changed, 5024 insertions, 0 deletions
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt new file mode 100644 index 0000000..1cbf11c --- /dev/null +++ b/lib/Basic/CMakeLists.txt @@ -0,0 +1,24 @@ +set(LLVM_NO_RTTI 1) + +add_clang_library(clangBasic + ConvertUTF.c + Diagnostic.cpp + FileManager.cpp + IdentifierTable.cpp + SourceLocation.cpp + SourceManager.cpp + TargetInfo.cpp + Targets.cpp + TokenKinds.cpp + ) + +add_dependencies(clangBasic + ClangDiagnosticAnalysis + ClangDiagnosticAST + ClangDiagnosticCommon + ClangDiagnosticDriver + ClangDiagnosticFrontend + ClangDiagnosticGroups + ClangDiagnosticLex + ClangDiagnosticParse + ClangDiagnosticSema) diff --git a/lib/Basic/ConvertUTF.c b/lib/Basic/ConvertUTF.c new file mode 100644 index 0000000..e5dd3e6 --- /dev/null +++ b/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/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp new file mode 100644 index 0000000..3b3d61b --- /dev/null +++ b/lib/Basic/Diagnostic.cpp @@ -0,0 +1,788 @@ +//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Diagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.h" + +#include "clang/Lex/LexDiagnostic.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Analysis/AnalysisDiagnostic.h" +#include "clang/Driver/DriverDiagnostic.h" + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.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; + 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) \ + { diag::ENUM, DEFAULT_MAPPING, CLASS, 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 } +}; +#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] < StaticDiagInfo[i] && + "Improperly sorted diag info"); + IsFirst = false; + } +#endif + + // Search the diagnostic table with a binary search. + StaticDiagInfoRec Find = { DiagID, 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; +} + +/// 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, const char *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, + 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; + SuppressSystemWarnings = false; + ExtBehavior = Ext_Ignore; + + ErrorOccurred = false; + FatalErrorOccurred = false; + NumDiagnostics = 0; + NumErrors = 0; + CustomDiagInfo = 0; + CurDiagID = ~0U; + LastDiagLevel = Ignored; + + ArgToStringFn = DummyArgToStringFn; + ArgToStringCookie = 0; + + // Set all mappings to 'unset'. + memset(DiagMappings, 0, sizeof(DiagMappings)); +} + +Diagnostic::~Diagnostic() { + delete CustomDiagInfo; +} + +/// getCustomDiagID - Return an ID for a diagnostic with the specified message +/// and level. If this is the first request for this diagnosic, it is +/// registered and created, otherwise the existing ID is returned. +unsigned Diagnostic::getCustomDiagID(Level L, const char *Message) { + if (CustomDiagInfo == 0) + CustomDiagInfo = new diag::CustomDiagInfo(); + return CustomDiagInfo->getOrCreateDiagID(L, Message, *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. +/// +bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID) { + return DiagID < diag::DIAG_UPPER_LIMIT && + getBuiltinDiagClass(DiagID) == CLASS_EXTENSION; +} + + +/// 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); +} + +/// 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; + break; + case diag::MAP_ERROR: + Result = Diagnostic::Error; + 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; + 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; + } + + // 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 char *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 char *SubGroups = Group->SubGroups) { + for (; *SubGroups != (char)-1; ++SubGroups) + MapGroupMembers(&OptionTable[(unsigned char)*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. +void Diagnostic::ProcessDiag() { + DiagnosticInfo Info(this); + + // 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) + return; + + // 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; + + // If this diagnostic is in a system header and is not a clang error, suppress + // it. + if (SuppressSystemWarnings && !ShouldEmitInSystemHeader && + Info.getLocation().isValid() && + Info.getLocation().getSpellingLoc().isInSystemHeader() && + (DiagLevel != Diagnostic::Note || LastDiagLevel == Diagnostic::Ignored)) { + LastDiagLevel = Diagnostic::Ignored; + return; + } + + if (DiagLevel >= Diagnostic::Error) { + ErrorOccurred = true; + ++NumErrors; + } + + // Finally, report it. + Client->HandleDiagnostic(DiagLevel, Info); + if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics; + + CurDiagID = ~0U; +} + + +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); +} + +/// 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(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 = std::find(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 = std::find(Argument, ArgumentEnd, '|'); + // Add the value to the output string. + OutStr.append(Argument, EndPtr); +} + +/// 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'); +} + + +/// 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 = std::find(Argument, ArgumentEnd, '|'); + OutStr.append(Argument, ExprEnd); + return; + } + Argument = std::find(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); + + 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 (DiagStr[1] == '%') { + OutStr.push_back('%'); // %% -> %. + 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; + + for (; DiagStr[0] != '}'; ++DiagStr) + assert(DiagStr[0] && "Mismatched {}'s in diagnostic string!"); + ArgumentLen = DiagStr-Argument; + ++DiagStr; // Skip }. + } + } + + assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic"); + unsigned ArgNo = *DiagStr++ - '0'; + + switch (getArgKind(ArgNo)) { + // ---- 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((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 { + assert(ModifierLen == 0 && "Unknown integer modifier"); + // FIXME: Optimize + std::string S = llvm::itostr(Val); + OutStr.append(S.begin(), S.end()); + } + break; + } + case Diagnostic::ak_uint: { + unsigned Val = getArgUInt(ArgNo); + + if (ModifierIs(Modifier, ModifierLen, "select")) { + HandleSelectModifier(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 { + assert(ModifierLen == 0 && "Unknown integer modifier"); + + // FIXME: Optimize + std::string S = llvm::utostr_32(Val); + OutStr.append(S.begin(), S.end()); + } + 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; + } + + OutStr.push_back('\''); + OutStr.append(II->getName(), II->getName() + II->getLength()); + OutStr.push_back('\''); + break; + } + case Diagnostic::ak_qualtype: + case Diagnostic::ak_declarationname: + case Diagnostic::ak_nameddecl: + getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo), + Modifier, ModifierLen, + Argument, ArgumentLen, OutStr); + break; + } + } +} + +/// 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; } diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp new file mode 100644 index 0000000..cc25d33 --- /dev/null +++ b/lib/Basic/FileManager.cpp @@ -0,0 +1,302 @@ +///===--- 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/System/Path.h" +#include "llvm/Support/Streams.h" +#include "llvm/Config/config.h" +using namespace clang; + +// FIXME: Enhance libsystem to support inode and other fields. +#include <sys/stat.h> + +#if defined(_MSC_VER) +#define S_ISDIR(s) (_S_IFDIR & s) +#endif + +/// NON_EXISTENT_DIR - A special value distinct from null that is used to +/// represent a dir name that doesn't exist on the disk. +#define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1) + +//===----------------------------------------------------------------------===// +// 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; +} + +/// getDirectory - Lookup, cache, and verify the specified directory. This +/// returns null if the directory doesn't exist. +/// +const DirectoryEntry *FileManager::getDirectory(const char *NameStart, + const char *NameEnd) { + ++NumDirLookups; + llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt = + DirEntries.GetOrCreateValue(NameStart, NameEnd); + + // See if there is already an entry in the map. + if (NamedDirEnt.getValue()) + return NamedDirEnt.getValue() == NON_EXISTENT_DIR + ? 0 : NamedDirEnt.getValue(); + + ++NumDirCacheMisses; + + // By default, initialize it to invalid. + NamedDirEnt.setValue(NON_EXISTENT_DIR); + + // Get the null-terminated directory name as stored as the key of the + // DirEntries map. + const char *InterndDirName = NamedDirEnt.getKeyData(); + + // Check to see if the directory exists. + struct stat StatBuf; + if (stat_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); + + // Figure out what directory it is in. If the string contains a / in it, + // strip off everything after it. + // FIXME: this logic should be in sys::Path. + const char *SlashPos = NameEnd-1; + while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0])) + --SlashPos; + + const DirectoryEntry *DirInfo; + if (SlashPos < NameStart) { + // Use the current directory if file has no path component. + const char *Name = "."; + DirInfo = getDirectory(Name, Name+1); + } else if (SlashPos == NameEnd-1) + return 0; // If filename ends with a /, it's a directory. + else + DirInfo = getDirectory(NameStart, SlashPos); + + if (DirInfo == 0) // Directory doesn't exist, file can't exist. + return 0; + + // Get the null-terminated file name as stored as the key of the + // FileEntries map. + const char *InterndFileName = NamedFileEnt.getKeyData(); + + // FIXME: Use the directory info to prune this, before doing the stat syscall. + // FIXME: This will reduce the # syscalls. + + // Nope, there isn't. Check to see if the file exists. + struct stat StatBuf; + //llvm::cerr << "STATING: " << Filename; + if (stat_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::cerr << ": Not existing\n"; + return 0; + } + //llvm::cerr << ": exists\n"; + + // It exists. See if we have already opened a file with the same inode. + // This occurs when one dir is symlinked to another, for example. + FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf); + + NamedFileEnt.setValue(&UFE); + if (UFE.getName()) // Already have an entry with this inode, return it. + return &UFE; + + // Otherwise, we don't have this directory yet, add it. + // FIXME: Change the name to be a char* that points back to the 'FileEntries' + // key. + UFE.Name = InterndFileName; + UFE.Size = StatBuf.st_size; + UFE.ModTime = StatBuf.st_mtime; + UFE.Dir = DirInfo; + UFE.UID = NextFileUID++; + return &UFE; +} + +void FileManager::PrintStats() const { + llvm::cerr << "\n*** File Manager Stats:\n"; + llvm::cerr << UniqueFiles.size() << " files found, " + << UniqueDirs.size() << " dirs found.\n"; + llvm::cerr << NumDirLookups << " dir lookups, " + << NumDirCacheMisses << " dir cache misses.\n"; + llvm::cerr << NumFileLookups << " file lookups, " + << NumFileCacheMisses << " file cache misses.\n"; + + //llvm::cerr << PagesMapped << BytesOfPagesMapped << FSLookups; +} + +int MemorizeStatCalls::stat(const char *path, struct stat *buf) { + int result = ::stat(path, buf); + + if (result != 0) { + // Cache failed 'stat' results. + struct stat empty; + StatCalls[path] = StatResult(result, empty); + } + else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) { + // Cache file 'stat' results and directories with absolutely + // paths. + StatCalls[path] = StatResult(result, *buf); + } + + return result; +} diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp new file mode 100644 index 0000000..cf78da98 --- /dev/null +++ b/lib/Basic/IdentifierTable.cpp @@ -0,0 +1,388 @@ +//===--- 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 <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 + }; +} + +/// AddKeyword - This method is used to associate a token ID with specific +/// identifiers because they are language keywords. This causes the lexer to +/// automatically map matching identifiers to specialized token codes. +/// +/// The C90/C99/CPP/CPP0x flags are set to 0 if the token should be +/// enabled in the specified langauge, set to 1 if it is an extension +/// in the specified language, and set to 2 if disabled in the +/// specified language. +static void AddKeyword(const char *Keyword, unsigned KWLen, + tok::TokenKind TokenCode, 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.GNUMode && (Flags & KEYGNU)) AddResult = 1; + else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1; + + // Don't add this keyword if disabled in this language. + if (AddResult == 0) return; + + IdentifierInfo &Info = Table.get(Keyword, Keyword+KWLen); + Info.setTokenID(TokenCode); + Info.setIsExtensionToken(AddResult == 1); +} + +/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative +/// representations. +static void AddCXXOperatorKeyword(const char *Keyword, unsigned KWLen, + tok::TokenKind TokenCode, + IdentifierTable &Table) { + IdentifierInfo &Info = Table.get(Keyword, Keyword + KWLen); + Info.setTokenID(TokenCode); + Info.setIsCPlusPlusOperatorKeyword(); +} + +/// AddObjCKeyword - Register an Objective-C @keyword like "class" "selector" or +/// "property". +static void AddObjCKeyword(tok::ObjCKeywordKind ObjCID, + const char *Name, unsigned NameLen, + IdentifierTable &Table) { + Table.get(Name, Name+NameLen).setObjCKeywordID(ObjCID); +} + +/// AddKeywords - Add all keywords to the symbol table. +/// +void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { + // Add keywords and tokens for the current language. +#define KEYWORD(NAME, FLAGS) \ + AddKeyword(#NAME, strlen(#NAME), tok::kw_ ## NAME, \ + FLAGS, LangOpts, *this); +#define ALIAS(NAME, TOK, FLAGS) \ + AddKeyword(NAME, strlen(NAME), tok::kw_ ## TOK, \ + FLAGS, LangOpts, *this); +#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \ + if (LangOpts.CXXOperatorNames) \ + AddCXXOperatorKeyword(#NAME, strlen(#NAME), tok::ALIAS, *this); +#define OBJC1_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC1) \ + AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this); +#define OBJC2_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC2) \ + AddObjCKeyword(tok::objc_##NAME, #NAME, strlen(#NAME), *this); +#include "clang/Basic/TokenKinds.def" +} + +tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { + // We use a perfect hash function here involving the length of the keyword, + // the first and third character. For preprocessor ID's there are no + // collisions (if there were, the switch below would complain about duplicate + // case values). Note that this depends on 'if' being null terminated. + +#define HASH(LEN, FIRST, THIRD) \ + (LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31) +#define CASE(LEN, FIRST, THIRD, NAME) \ + case HASH(LEN, FIRST, THIRD): \ + return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME + + unsigned Len = getLength(); + if (Len < 2) return tok::pp_not_keyword; + const char *Name = getName(); + switch (HASH(Len, Name[0], Name[2])) { + default: return tok::pp_not_keyword; + CASE( 2, 'i', '\0', if); + CASE( 4, 'e', 'i', elif); + CASE( 4, 'e', 's', else); + CASE( 4, 'l', 'n', line); + CASE( 4, 's', 'c', sccs); + CASE( 5, 'e', 'd', endif); + CASE( 5, 'e', 'r', error); + CASE( 5, 'i', 'e', ident); + CASE( 5, 'i', 'd', ifdef); + CASE( 5, 'u', 'd', undef); + + CASE( 6, 'a', 's', assert); + CASE( 6, 'd', 'f', define); + CASE( 6, 'i', 'n', ifndef); + CASE( 6, 'i', 'p', import); + CASE( 6, 'p', 'a', pragma); + + CASE( 7, 'd', 'f', defined); + CASE( 7, 'i', 'c', include); + CASE( 7, 'w', 'r', warning); + + CASE( 8, 'u', 'a', unassert); + CASE(12, 'i', 'c', include_next); + + 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 { + std::string Result; + unsigned Length = 0; + for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { + if (*I) + Length += (*I)->getLength(); + ++Length; // : + } + + Result.reserve(Length); + + for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { + if (*I) + Result.insert(Result.end(), (*I)->getName(), + (*I)->getName()+(*I)->getLength()); + Result.push_back(':'); + } + + return Result; +} + +std::string Selector::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(); + + std::string Res = II ? II->getName() : ""; + Res += ":"; + return Res; + } + + // 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); +} + diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile new file mode 100644 index 0000000..3fd6c2c --- /dev/null +++ b/lib/Basic/Makefile @@ -0,0 +1,22 @@ +##===- clang/lib/Basic/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the Basic library for the C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangBasic +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp new file mode 100644 index 0000000..f21ec8b --- /dev/null +++ b/lib/Basic/SourceLocation.cpp @@ -0,0 +1,125 @@ +//==--- 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() const { + assert(isValid()); + return SrcMgr->getInstantiationLineNumber(*this); +} + +unsigned FullSourceLoc::getInstantiationColumnNumber() const { + assert(isValid()); + return SrcMgr->getInstantiationColumnNumber(*this); +} + +unsigned FullSourceLoc::getSpellingLineNumber() const { + assert(isValid()); + return SrcMgr->getSpellingLineNumber(*this); +} + +unsigned FullSourceLoc::getSpellingColumnNumber() const { + assert(isValid()); + return SrcMgr->getSpellingColumnNumber(*this); +} + +bool FullSourceLoc::isInSystemHeader() const { + assert(isValid()); + return SrcMgr->isInSystemHeader(*this); +} + +const char *FullSourceLoc::getCharacterData() const { + assert(isValid()); + return SrcMgr->getCharacterData(*this); +} + +const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const { + assert(isValid()); + return SrcMgr->getBuffer(SrcMgr->getFileID(*this)); +} + +std::pair<const char*, const char*> FullSourceLoc::getBufferData() const { + const llvm::MemoryBuffer *Buf = getBuffer(); + return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd()); +} + +std::pair<FileID, unsigned> FullSourceLoc::getDecomposedLoc() const { + return SrcMgr->getDecomposedLoc(*this); +} diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp new file mode 100644 index 0000000..7d2d0ae --- /dev/null +++ b/lib/Basic/SourceManager.cpp @@ -0,0 +1,943 @@ +//===--- 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/FileManager.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Path.h" +#include "llvm/Support/Streams.h" +#include <algorithm> +#include <iostream> +using namespace clang; +using namespace SrcMgr; +using llvm::MemoryBuffer; + +//===----------------------------------------------------------------------===// +// SourceManager Helper Classes +//===----------------------------------------------------------------------===// + +ContentCache::~ContentCache() { + delete Buffer; +} + +/// 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 ? Buffer->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 Entry ? Entry->getSize() : Buffer->getBufferSize(); +} + +const llvm::MemoryBuffer *ContentCache::getBuffer() const { + // Lazily create the Buffer for ContentCaches that wrap files. + if (!Buffer && Entry) { + // FIXME: Should we support a way to not have to do this check over + // and over if we cannot open the file? + Buffer = MemoryBuffer::getFile(Entry->getName(), 0, Entry->getSize()); + } + return Buffer; +} + +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) { + SLocEntry NewEntry = SLocEntry::get(NextOffset, + FileInfo::get(IncludePos, File, + FileCharacter)); + 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; + return LastFileIDLookup = FileID::get(PreallocatedID); + } + + 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. + return LastFileIDLookup = FileID::get(SLocEntryTable.size()-1); +} + +/// 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)); +} + +/// getBufferData - Return a pointer to the start and end of the source buffer +/// data for the specified FileID. +std::pair<const char*, const char*> +SourceManager::getBufferData(FileID FID) const { + const llvm::MemoryBuffer *Buf = getBuffer(FID); + return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd()); +} + + +//===----------------------------------------------------------------------===// +// 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 { + std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc); + Loc = getSLocEntry(LocInfo.first).getInstantiation() + .getInstantiationLocStart(); + Loc = Loc.getFileLocWithOffset(LocInfo.second); + } 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) 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. + return getSLocEntry(LocInfo.first).getFile().getContentCache() + ->getBuffer()->getBufferStart() + 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) const { + const char *Buf = getBuffer(FID)->getBufferStart(); + + unsigned LineStart = FilePos; + while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r') + --LineStart; + return FilePos-LineStart+1; +} + +unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc) const { + if (Loc.isInvalid()) return 0; + std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc); + return getColumnNumber(LocInfo.first, LocInfo.second); +} + +unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc) const { + if (Loc.isInvalid()) return 0; + std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + return getColumnNumber(LocInfo.first, LocInfo.second); +} + + + +static void ComputeLineNumbers(ContentCache* FI, + llvm::BumpPtrAllocator &Alloc) DISABLE_INLINE; +static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){ + // Note that calling 'getBuffer()' may lazily page in the file. + const MemoryBuffer *Buffer = FI->getBuffer(); + + // 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) 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) + ComputeLineNumbers(Content, ContentCacheAlloc); + + // 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) const { + if (Loc.isInvalid()) return 0; + std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); + return getLineNumber(LocInfo.first, LocInfo.second); +} +unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc) 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) const { + if (Loc.isInvalid()) return "<invalid loc>"; + + return getBuffer(getFileID(Loc))->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 = + C->Entry ? C->Entry->getName() : C->getBuffer()->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. +//===----------------------------------------------------------------------===// + + +/// PrintStats - Print statistics to stderr. +/// +void SourceManager::PrintStats() const { + llvm::cerr << "\n*** Source Manager Stats:\n"; + llvm::cerr << FileInfos.size() << " files mapped, " << MemBufferInfos.size() + << " mem buffers mapped.\n"; + llvm::cerr << 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::cerr << NumFileBytesMapped << " bytes of files mapped, " + << NumLineNumsComputed << " files with line #'s computed.\n"; + llvm::cerr << "FileID scans: " << NumLinearScans << " linear, " + << NumBinaryProbes << " binary.\n"; +} + +ExternalSLocEntrySource::~ExternalSLocEntrySource() { } diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp new file mode 100644 index 0000000..1e8ca2b --- /dev/null +++ b/lib/Basic/TargetInfo.cpp @@ -0,0 +1,295 @@ +//===--- 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 "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. + CharIsSigned = true; + TLSSupported = true; + PointerWidth = PointerAlign = 32; + WCharWidth = WCharAlign = 32; + IntWidth = IntAlign = 32; + LongWidth = LongAlign = 32; + LongLongWidth = LongLongAlign = 64; + FloatWidth = 32; + FloatAlign = 32; + DoubleWidth = 64; + DoubleAlign = 64; + LongDoubleWidth = 64; + LongDoubleAlign = 64; + IntMaxTWidth = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntMaxType = SignedLongLong; + UIntMaxType = UnsignedLongLong; + IntPtrType = SignedLong; + WCharType = SignedInt; + 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"; + UserLabelPrefix = "_"; +} + +// 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"; + } +} + +//===----------------------------------------------------------------------===// + + +static void removeGCCRegisterPrefix(const char *&Name) { + if (Name[0] == '%' || Name[0] == '#') + Name++; +} + +/// isValidGCCRegisterName - Returns whether the passed in string +/// is a valid register name according to GCC. This is used by Sema for +/// inline asm statements. +bool TargetInfo::isValidGCCRegisterName(const char *Name) const { + const char * const *Names; + unsigned NumNames; + + // Get rid of any register prefix. + removeGCCRegisterPrefix(Name); + + + if (strcmp(Name, "memory") == 0 || + strcmp(Name, "cc") == 0) + return true; + + getGCCRegNames(Names, NumNames); + + // If we have a number it maps to an entry in the register name array. + if (isdigit(Name[0])) { + char *End; + int n = (int)strtol(Name, &End, 0); + if (*End == 0) + return n >= 0 && (unsigned)n < NumNames; + } + + // Check register names. + for (unsigned i = 0; i < NumNames; i++) { + if (strcmp(Name, Names[i]) == 0) + return true; + } + + // Now check aliases. + const GCCRegAlias *Aliases; + unsigned NumAliases; + + getGCCRegAliases(Aliases, NumAliases); + for (unsigned i = 0; i < NumAliases; i++) { + for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { + if (!Aliases[i].Aliases[j]) + break; + if (strcmp(Aliases[i].Aliases[j], Name) == 0) + return true; + } + } + + return false; +} + +const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const { + assert(isValidGCCRegisterName(Name) && "Invalid register passed in"); + + removeGCCRegisterPrefix(Name); + + const char * const *Names; + unsigned NumNames; + + getGCCRegNames(Names, NumNames); + + // First, check if we have a number. + if (isdigit(Name[0])) { + char *End; + int n = (int)strtol(Name, &End, 0); + if (*End == 0) { + assert(n >= 0 && (unsigned)n < NumNames && + "Out of bounds register number!"); + return Names[n]; + } + } + + // Now check aliases. + const GCCRegAlias *Aliases; + unsigned NumAliases; + + getGCCRegAliases(Aliases, NumAliases); + for (unsigned i = 0; i < NumAliases; i++) { + for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { + if (!Aliases[i].Aliases[j]) + break; + if (strcmp(Aliases[i].Aliases[j], Name) == 0) + return Aliases[i].Register; + } + } + + return Name; +} + +bool TargetInfo::validateOutputConstraint(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 '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. + 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/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp new file mode 100644 index 0000000..4b94bcf --- /dev/null +++ b/lib/Basic/Targets.cpp @@ -0,0 +1,1500 @@ +//===--- 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. +// +//===----------------------------------------------------------------------===// + +// FIXME: Layering violation +#include "clang/AST/Builtins.h" +#include "clang/AST/TargetBuiltins.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/SmallString.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Common code shared among targets. +//===----------------------------------------------------------------------===// + +static void Define(std::vector<char> &Buf, const char *Macro, + const char *Val = "1") { + const char *Def = "#define "; + Buf.insert(Buf.end(), Def, Def+strlen(Def)); + Buf.insert(Buf.end(), Macro, Macro+strlen(Macro)); + Buf.push_back(' '); + Buf.insert(Buf.end(), Val, Val+strlen(Val)); + Buf.push_back('\n'); +} + +/// 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(std::vector<char> &Buf, const char *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) + Define(Buf, MacroName); + + // Define __unix. + llvm::SmallString<20> TmpStr; + TmpStr = "__"; + TmpStr += MacroName; + Define(Buf, TmpStr.c_str()); + + // Define __unix__. + TmpStr += "__"; + Define(Buf, TmpStr.c_str()); +} + +//===----------------------------------------------------------------------===// +// Defines specific to certain operating systems. +//===----------------------------------------------------------------------===// + +static void getSolarisDefines(const LangOptions &Opts, std::vector<char> &Defs) { + DefineStd(Defs, "sun", Opts); + DefineStd(Defs, "unix", Opts); + Define(Defs, "__ELF__"); + Define(Defs, "__svr4__"); + Define(Defs, "__SVR4"); +} + +static void getFreeBSDDefines(const LangOptions &Opts, bool is64Bit, + const char *Triple, std::vector<char> &Defs) { + // FreeBSD defines; list based off of gcc output + + const char *FreeBSD = strstr(Triple, "-freebsd"); + FreeBSD += strlen("-freebsd"); + char release[] = "X"; + release[0] = FreeBSD[0]; + char version[] = "X00001"; + version[0] = FreeBSD[0]; + + Define(Defs, "__FreeBSD__", release); + Define(Defs, "__FreeBSD_cc_version", version); + Define(Defs, "__KPRINTF_ATTRIBUTE__"); + DefineStd(Defs, "unix", Opts); + Define(Defs, "__ELF__", "1"); + if (is64Bit) { + Define(Defs, "__LP64__"); + } +} + +static void getDragonFlyDefines(const LangOptions &Opts, + std::vector<char> &Defs) { + // DragonFly defines; list based off of gcc output + Define(Defs, "__DragonFly__"); + Define(Defs, "__DragonFly_cc_version", "100001"); + Define(Defs, "__ELF__"); + Define(Defs, "__KPRINTF_ATTRIBUTE__"); + Define(Defs, "__tune_i386__"); + DefineStd(Defs, "unix", Opts); +} + +static void getLinuxDefines(const LangOptions &Opts, std::vector<char> &Defs) { + // Linux defines; list based off of gcc output + DefineStd(Defs, "unix", Opts); + DefineStd(Defs, "linux", Opts); + Define(Defs, "__gnu_linux__"); + Define(Defs, "__ELF__", "1"); +} + +/// getDarwinNumber - Parse the 'darwin number' out of the specific targe +/// triple. For example, if we have darwin8.5 return 8,5,0. If any entry is +/// not defined, return 0's. Return true if we have -darwin in the string or +/// false otherwise. +static bool getDarwinNumber(const char *Triple, unsigned &Maj, unsigned &Min, unsigned &Revision) { + Maj = Min = Revision = 0; + const char *Darwin = strstr(Triple, "-darwin"); + if (Darwin == 0) return false; + + Darwin += strlen("-darwin"); + if (Darwin[0] < '0' || Darwin[0] > '9') + return true; + + Maj = Darwin[0]-'0'; + ++Darwin; + + // Handle "darwin11". + if (Maj == 1 && Darwin[0] >= '0' && Darwin[0] <= '9') { + Maj = Maj*10 + (Darwin[0] - '0'); + ++Darwin; + } + + // Handle minor version: 10.4.9 -> darwin8.9 -> "1049" + if (Darwin[0] != '.') + return true; + + ++Darwin; + if (Darwin[0] < '0' || Darwin[0] > '9') + return true; + + Min = Darwin[0]-'0'; + ++Darwin; + + // Handle 10.4.11 -> darwin8.11 + if (Min == 1 && Darwin[0] >= '0' && Darwin[0] <= '9') { + Min = Min*10 + (Darwin[0] - '0'); + ++Darwin; + } + + // Handle revision darwin8.9.1 + if (Darwin[0] != '.') + return true; + + ++Darwin; + if (Darwin[0] < '0' || Darwin[0] > '9') + return true; + + Revision = Darwin[0]-'0'; + ++Darwin; + + if (Revision == 1 && Darwin[0] >= '0' && Darwin[0] <= '9') { + Revision = Revision*10 + (Darwin[0] - '0'); + ++Darwin; + } + + return true; +} + +static void getDarwinDefines(std::vector<char> &Defs, const LangOptions &Opts) { + Define(Defs, "__APPLE__"); + Define(Defs, "__MACH__"); + Define(Defs, "OBJC_NEW_PROPERTIES"); + + // __weak is always defined, for use in blocks and with objc pointers. + Define(Defs, "__weak", "__attribute__((objc_gc(weak)))"); + + // Darwin defines __strong even in C mode (just to nothing). + if (!Opts.ObjC1 || Opts.getGCMode() == LangOptions::NonGC) + Define(Defs, "__strong", ""); + else + Define(Defs, "__strong", "__attribute__((objc_gc(strong)))"); +} + +static void getDarwinOSXDefines(std::vector<char> &Defs, const char *Triple) { + // Figure out which "darwin number" the target triple is. "darwin9" -> 10.5. + unsigned Maj, Min, Rev; + if (getDarwinNumber(Triple, Maj, Min, Rev)) { + char MacOSXStr[] = "1000"; + if (Maj >= 4 && Maj <= 13) { // 10.0-10.9 + // darwin7 -> 1030, darwin8 -> 1040, darwin9 -> 1050, etc. + MacOSXStr[2] = '0' + Maj-4; + } + + // Handle minor version: 10.4.9 -> darwin8.9 -> "1049" + // Cap 10.4.11 -> darwin8.11 -> "1049" + MacOSXStr[3] = std::min(Min, 9U)+'0'; + Define(Defs, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", MacOSXStr); + } +} + +static void getDarwinIPhoneOSDefines(std::vector<char> &Defs, + const char *Triple) { + // Figure out which "darwin number" the target triple is. "darwin9" -> 10.5. + unsigned Maj, Min, Rev; + if (getDarwinNumber(Triple, Maj, Min, Rev)) { + // When targetting iPhone OS, interpret the minor version and + // revision as the iPhone OS version + char iPhoneOSStr[] = "10000"; + if (Min >= 2 && Min <= 9) { // iPhone OS 2.0-9.0 + // darwin9.2.0 -> 20000, darwin9.3.0 -> 30000, etc. + iPhoneOSStr[0] = '0' + Min; + } + + // Handle minor version: 2.2 -> darwin9.2.2 -> 20200 + iPhoneOSStr[2] = std::min(Rev, 9U)+'0'; + Define(Defs, "__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", + iPhoneOSStr); + } +} + +/// GetDarwinLanguageOptions - Set the default language options for darwin. +static void GetDarwinLanguageOptions(LangOptions &Opts, + const char *Triple) { + Opts.NeXTRuntime = true; + + unsigned Maj, Min, Rev; + if (!getDarwinNumber(Triple, Maj, Min, Rev)) + return; + + // Blocks default to on for 10.6 (darwin10) and beyond. + // As does nonfragile-abi for 64bit mode + if (Maj > 9) + Opts.Blocks = 1; + + if (Maj >= 9 && Opts.ObjC1 && !strncmp(Triple, "x86_64", 6)) + Opts.ObjCNonFragileABI = 1; +} + + +//===----------------------------------------------------------------------===// +// 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) { + CharIsSigned = false; + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + Records = BuiltinInfo; + NumRecords = clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) 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 const char *getTargetPrefix() const { + return "ppc"; + } + 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/AST/PPCBuiltins.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, + std::vector<char> &Defs) const { + // Target identification. + Define(Defs, "__ppc__"); + Define(Defs, "_ARCH_PPC"); + Define(Defs, "__POWERPC__"); + if (PointerWidth == 64) { + Define(Defs, "_ARCH_PPC64"); + Define(Defs, "_LP64"); + Define(Defs, "__LP64__"); + Define(Defs, "__ppc64__"); + } else { + Define(Defs, "__ppc__"); + } + + // Target properties. + Define(Defs, "_BIG_ENDIAN"); + Define(Defs, "__BIG_ENDIAN__"); + + // Subtarget options. + Define(Defs, "__NATURAL_ALIGNMENT__"); + Define(Defs, "__REGISTER_PREFIX__", ""); + + // FIXME: Should be controlled by command line option. + Define(Defs, "__LONG_DOUBLE_128__"); +} + + +const char * const PPCTargetInfo::GCCRegNames[] = { + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "30", "31", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "30", "31", + "mq", "lr", "ctr", "ap", + "0", "1", "2", "3", "4", "5", "6", "7", + "xer", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15", + "16", "17", "18", "19", "20", "21", "22", "23", + "24", "25", "26", "27", "28", "29", "30", "31", + "vrsave", "vscr", + "spe_acc", "spefscr", + "sfp" +}; + +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. + { { "cc", "cr0", "fr0", "r0", "v0"}, "0" }, + { { "cr1", "fr1", "r1", "sp", "v1"}, "1" }, + { { "cr2", "fr2", "r2", "toc", "v2"}, "2" }, + { { "cr3", "fr3", "r3", "v3"}, "3" }, + { { "cr4", "fr4", "r4", "v4"}, "4" }, + { { "cr5", "fr5", "r5", "v5"}, "5" }, + { { "cr6", "fr6", "r6", "v6"}, "6" }, + { { "cr7", "fr7", "r7", "v7"}, "7" }, + { { "fr8", "r8", "v8"}, "8" }, + { { "fr9", "r9", "v9"}, "9" }, + { { "fr10", "r10", "v10"}, "10" }, + { { "fr11", "r11", "v11"}, "11" }, + { { "fr12", "r12", "v12"}, "12" }, + { { "fr13", "r13", "v13"}, "13" }, + { { "fr14", "r14", "v14"}, "14" }, + { { "fr15", "r15", "v15"}, "15" }, + { { "fr16", "r16", "v16"}, "16" }, + { { "fr17", "r17", "v17"}, "17" }, + { { "fr18", "r18", "v18"}, "18" }, + { { "fr19", "r19", "v19"}, "19" }, + { { "fr20", "r20", "v20"}, "20" }, + { { "fr21", "r21", "v21"}, "21" }, + { { "fr22", "r22", "v22"}, "22" }, + { { "fr23", "r23", "v23"}, "23" }, + { { "fr24", "r24", "v24"}, "24" }, + { { "fr25", "r25", "v25"}, "25" }, + { { "fr26", "r26", "v26"}, "26" }, + { { "fr27", "r27", "v27"}, "27" }, + { { "fr28", "r28", "v28"}, "28" }, + { { "fr29", "r29", "v29"}, "29" }, + { { "fr30", "r30", "v30"}, "30" }, + { { "fr31", "r31", "v31"}, "31" }, +}; + +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"; + } +}; +} // end anonymous namespace. + +namespace { +class PPC64TargetInfo : public PPCTargetInfo { +public: + PPC64TargetInfo(const std::string& triple) : PPCTargetInfo(triple) { + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + 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"; + } +}; +} // end anonymous namespace. + + +namespace { +class DarwinPPCTargetInfo : public PPC32TargetInfo { +public: + DarwinPPCTargetInfo(const std::string& triple) : PPC32TargetInfo(triple) {} + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + PPC32TargetInfo::getTargetDefines(Opts, Defines); + getDarwinDefines(Defines, Opts); + getDarwinOSXDefines(Defines, getTargetTriple()); + } + + /// getDefaultLangOptions - Allow the target to specify default settings for + /// various language options. These may be overridden by command line + /// options. + virtual void getDefaultLangOptions(LangOptions &Opts) { + GetDarwinLanguageOptions(Opts, getTargetTriple()); + } +}; +} // end anonymous namespace. + +namespace { +class DarwinPPC64TargetInfo : public PPC64TargetInfo { +public: + DarwinPPC64TargetInfo(const std::string& triple) : PPC64TargetInfo(triple) {} + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + PPC64TargetInfo::getTargetDefines(Opts, Defines); + getDarwinDefines(Defines, Opts); + getDarwinOSXDefines(Defines, getTargetTriple()); + } + + /// getDefaultLangOptions - Allow the target to specify default settings for + /// various language options. These may be overridden by command line + /// options. + virtual void getDefaultLangOptions(LangOptions &Opts) { + GetDarwinLanguageOptions(Opts, getTargetTriple()); + } +}; +} // 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/AST/X86Builtins.def" +}; + +const char *GCCRegNames[] = { + "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", + "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", + "argp", "flags", "fspr", "dirflag", "frame", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" +}; + +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; +public: + X86TargetInfo(const std::string& triple) + : TargetInfo(triple), SSELevel(NoMMXSSE) { + LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + Records = BuiltinInfo; + NumRecords = clang::X86::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + virtual const char *getTargetPrefix() const { + return "x86"; + } + 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, + std::vector<char> &Defines) 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(const llvm::StringMap<bool> &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; + + // 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); + 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. + if (!Features.count(Name) && Name != "sse4") + 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") + Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["ssse3"] = Features["sse41"] = Features["sse42"] = true; + else if (Name == "3dnow") + Features["3dnowa"] = true; + else if (Name == "3dnowa") + Features["3dnow"] = Features["3dnowa"] = 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 == "3dnow") + Features["3dnow"] = Features["3dnowa"] = false; + else if (Name == "3dnowa") + Features["3dnowa"] = false; + } + + return true; +} + +/// HandleTargetOptions - Perform initialization based on the user +/// configured set of features. +void X86TargetInfo::HandleTargetFeatures(const llvm::StringMap<bool>&Features) { + if (Features.lookup("sse42")) + SSELevel = SSE42; + else if (Features.lookup("sse41")) + SSELevel = SSE41; + else if (Features.lookup("ssse3")) + SSELevel = SSSE3; + else if (Features.lookup("sse3")) + SSELevel = SSE3; + else if (Features.lookup("sse2")) + SSELevel = SSE2; + else if (Features.lookup("sse")) + SSELevel = SSE1; + else if (Features.lookup("mmx")) + SSELevel = MMX; +} + +/// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines +/// that are not tied to a specific subtarget. +void X86TargetInfo::getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defs) const { + // Target identification. + if (PointerWidth == 64) { + Define(Defs, "_LP64"); + Define(Defs, "__LP64__"); + Define(Defs, "__amd64__"); + Define(Defs, "__amd64"); + Define(Defs, "__x86_64"); + Define(Defs, "__x86_64__"); + } else { + DefineStd(Defs, "i386", Opts); + } + + // Target properties. + Define(Defs, "__LITTLE_ENDIAN__"); + + // Subtarget options. + Define(Defs, "__nocona"); + Define(Defs, "__nocona__"); + Define(Defs, "__tune_nocona__"); + Define(Defs, "__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). + Define(Defs, "__NO_MATH_INLINES"); + + // Each case falls through to the previous one here. + switch (SSELevel) { + case SSE42: + Define(Defs, "__SSE4_2__"); + case SSE41: + Define(Defs, "__SSE4_1__"); + case SSSE3: + Define(Defs, "__SSSE3__"); + case SSE3: + Define(Defs, "__SSE3__"); + case SSE2: + Define(Defs, "__SSE2__"); + Define(Defs, "__SSE2_MATH__"); // -mfp-math=sse always implied. + case SSE1: + Define(Defs, "__SSE__"); + Define(Defs, "__SSE_MATH__"); // -mfp-math=sse always implied. + case MMX: + Define(Defs, "__MMX__"); + case NoMMXSSE: + 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. + 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"; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + RegParmMax = 3; + } + virtual const char *getVAListDeclaration() const { + return "typedef char* __builtin_va_list;"; + } +}; +} // end anonymous namespace + +namespace { +// x86-32 Darwin (OS X) target +class DarwinI386TargetInfo : public X86_32TargetInfo { +public: + DarwinI386TargetInfo(const std::string& triple) : 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"; + TLSSupported = false; + } + + virtual const char *getStringSymbolPrefix(bool IsConstant) const { + return IsConstant ? "\01LC" : "\01lC"; + } + + virtual const char *getUnicodeStringSymbolPrefix() const { + return "__utf16_string_"; + } + + virtual const char *getUnicodeStringSection() const { + return "__TEXT,__ustring"; + } + + virtual const char *getCFStringSymbolPrefix() const { + return "\01LC"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + X86_32TargetInfo::getTargetDefines(Opts, Defines); + getDarwinDefines(Defines, Opts); + getDarwinOSXDefines(Defines, getTargetTriple()); + } + + /// getDefaultLangOptions - Allow the target to specify default settings for + /// various language options. These may be overridden by command line + /// options. + virtual void getDefaultLangOptions(LangOptions &Opts) { + GetDarwinLanguageOptions(Opts, getTargetTriple()); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 FreeBSD target +class FreeBSDX86_32TargetInfo : public X86_32TargetInfo { +public: + FreeBSDX86_32TargetInfo(const std::string& triple) : + X86_32TargetInfo(triple) { } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + X86_32TargetInfo::getTargetDefines(Opts, Defines); + getFreeBSDDefines(Opts, 0, getTargetTriple(), Defines); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 DragonFly target +class DragonFlyX86_32TargetInfo : public X86_32TargetInfo { +public: + DragonFlyX86_32TargetInfo(const std::string& triple) : + X86_32TargetInfo(triple) { } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + X86_32TargetInfo::getTargetDefines(Opts, Defines); + getDragonFlyDefines(Opts, Defines); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 Linux target +class LinuxX86_32TargetInfo : public X86_32TargetInfo { +public: + LinuxX86_32TargetInfo(const std::string& triple) : X86_32TargetInfo(triple) { + UserLabelPrefix = ""; + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + X86_32TargetInfo::getTargetDefines(Opts, Defines); + getLinuxDefines(Opts, Defines); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 Solaris target +class SolarisX86_32TargetInfo : public X86_32TargetInfo { +public: + SolarisX86_32TargetInfo(const std::string& triple) : X86_32TargetInfo(triple) { + UserLabelPrefix = ""; + WCharType = SignedLong; + // FIXME: WIntType should be SignedLong + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + X86_32TargetInfo::getTargetDefines(Opts, Defines); + getSolarisDefines(Opts, Defines); + } +}; +} // 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; + // FIXME: Fix wchar_t. + // FIXME: We should probably enable -fms-extensions by default for + // this target. + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + X86_32TargetInfo::getTargetDefines(Opts, Defines); + // This list is based off of the the list of things MingW defines + Define(Defines, "_WIN32"); + DefineStd(Defines, "WIN32", Opts); + DefineStd(Defines, "WINNT", Opts); + Define(Defines, "_X86_"); + Define(Defines, "__MSVCRT__"); + } +}; +} // 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; + DoubleAlign = LongLongAlign = 64; + LongDoubleWidth = 128; + LongDoubleAlign = 128; + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + 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-f80:128:128"; + } + 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;" + "} __builtin_va_list[1];"; + } +}; +} // end anonymous namespace + +namespace { +// x86-64 FreeBSD target +class FreeBSDX86_64TargetInfo : public X86_64TargetInfo { +public: + FreeBSDX86_64TargetInfo(const std::string &triple) + : X86_64TargetInfo(triple) {} + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + X86_64TargetInfo::getTargetDefines(Opts, Defines); + getFreeBSDDefines(Opts, 1, getTargetTriple(), Defines); + } +}; +} // end anonymous namespace + +namespace { +// x86-64 Linux target +class LinuxX86_64TargetInfo : public X86_64TargetInfo { +public: + LinuxX86_64TargetInfo(const std::string& triple) : X86_64TargetInfo(triple) { + UserLabelPrefix = ""; + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + X86_64TargetInfo::getTargetDefines(Opts, Defines); + getLinuxDefines(Opts, Defines); + } +}; +} // end anonymous namespace + +namespace { +// x86-64 Solaris target +class SolarisX86_64TargetInfo : public X86_64TargetInfo { +public: + SolarisX86_64TargetInfo(const std::string& triple) : X86_64TargetInfo(triple) { + UserLabelPrefix = ""; + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + X86_64TargetInfo::getTargetDefines(Opts, Defines); + getSolarisDefines(Opts, Defines); + } +}; +} // end anonymous namespace + +namespace { +// x86-64 Darwin (OS X) target +class DarwinX86_64TargetInfo : public X86_64TargetInfo { +public: + DarwinX86_64TargetInfo(const std::string& triple) : X86_64TargetInfo(triple) { + TLSSupported = false; + } + + virtual const char *getStringSymbolPrefix(bool IsConstant) const { + return IsConstant ? "\01LC" : "\01lC"; + } + + virtual const char *getUnicodeStringSymbolPrefix() const { + return "__utf16_string_"; + } + + virtual const char *getUnicodeStringSection() const { + return "__TEXT,__ustring"; + } + + virtual const char *getCFStringSymbolPrefix() const { + return "\01L_unnamed_cfstring_"; + } + + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + X86_64TargetInfo::getTargetDefines(Opts, Defines); + getDarwinDefines(Defines, Opts); + getDarwinOSXDefines(Defines, getTargetTriple()); + } + + /// getDefaultLangOptions - Allow the target to specify default settings for + /// various language options. These may be overridden by command line + /// options. + virtual void getDefaultLangOptions(LangOptions &Opts) { + GetDarwinLanguageOptions(Opts, getTargetTriple()); + } +}; +} // end anonymous namespace. + +namespace { +class ARMTargetInfo : public TargetInfo { + enum { + Armv4t, + Armv5, + Armv6, + XScale + } ArmArch; +public: + ARMTargetInfo(const std::string& triple) : TargetInfo(triple) { + // FIXME: Are the defaults correct for ARM? + 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:64:64"; + if (triple.find("arm-") == 0 || triple.find("armv6-") == 0) + ArmArch = Armv6; + else if (triple.find("armv5-") == 0) + ArmArch = Armv5; + else if (triple.find("armv4t-") == 0) + ArmArch = Armv4t; + else if (triple.find("xscale-") == 0) + ArmArch = XScale; + else if (triple.find("armv") == 0) { + // FIXME: fuzzy match for other random weird arm triples. This is useful + // for the static analyzer and other clients, but probably should be + // re-evaluated when codegen is brought up. + ArmArch = Armv6; + } + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defs) const { + // Target identification. + Define(Defs, "__arm"); + Define(Defs, "__arm__"); + + // Target properties. + Define(Defs, "__LITTLE_ENDIAN__"); + + // Subtarget options. + if (ArmArch == Armv6) { + Define(Defs, "__ARM_ARCH_6K__"); + Define(Defs, "__THUMB_INTERWORK__"); + } else if (ArmArch == Armv5) { + Define(Defs, "__ARM_ARCH_5TEJ__"); + Define(Defs, "__THUMB_INTERWORK__"); + Define(Defs, "__SOFTFP__"); + } else if (ArmArch == Armv4t) { + Define(Defs, "__ARM_ARCH_4T__"); + Define(Defs, "__SOFTFP__"); + } else if (ArmArch == XScale) { + Define(Defs, "__ARM_ARCH_5TE__"); + Define(Defs, "__XSCALE__"); + Define(Defs, "__SOFTFP__"); + } + Define(Defs, "__ARMEL__"); + Define(Defs, "__APCS_32__"); + Define(Defs, "__VFP_FP__"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + // FIXME: Implement. + Records = 0; + NumRecords = 0; + } + virtual const char *getVAListDeclaration() const { + return "typedef char* __builtin_va_list;"; + } + virtual const char *getTargetPrefix() const { + return "arm"; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + // FIXME: Implement. + Names = 0; + NumNames = 0; + } + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + // FIXME: Implement. + Aliases = 0; + NumAliases = 0; + } + 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 ""; + } +}; +} // end anonymous namespace. + + +namespace { +class DarwinARMTargetInfo : public ARMTargetInfo { +public: + DarwinARMTargetInfo(const std::string& triple) : ARMTargetInfo(triple) { + TLSSupported = false; + } + + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + ARMTargetInfo::getTargetDefines(Opts, Defines); + getDarwinDefines(Defines, Opts); + getDarwinIPhoneOSDefines(Defines, getTargetTriple()); + } +}; +} // end anonymous namespace. + +namespace { +// arm FreeBSD target +class FreeBSDARMTargetInfo : public ARMTargetInfo { +public: + FreeBSDARMTargetInfo(const std::string& triple) : ARMTargetInfo(triple) {} + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + ARMTargetInfo::getTargetDefines(Opts, Defines); + getFreeBSDDefines(Opts, 0, getTargetTriple(), Defines); + } +}; +} // 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"; + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + DefineStd(Defines, "sparc", Opts); + Define(Defines, "__sparcv8"); + Define(Defines, "__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 const char *getTargetPrefix() const { + return "sparc"; + } + 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 SolarisSparcV8TargetInfo : public SparcV8TargetInfo { +public: + SolarisSparcV8TargetInfo(const std::string& triple) : + SparcV8TargetInfo(triple) { + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + WCharType = SignedLong; + // FIXME: WIntType should be SignedLong + UserLabelPrefix = ""; + } + + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + SparcV8TargetInfo::getTargetDefines(Opts, Defines); + getSolarisDefines(Opts, Defines); + } +}; +} // end anonymous namespace. + +namespace { + class PIC16TargetInfo : public TargetInfo{ + public: + PIC16TargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = false; + IntWidth = 16; + LongWidth = LongLongWidth = 32; + IntMaxTWidth = 32; + PointerWidth = 16; + IntAlign = 8; + LongAlign = LongLongAlign = 8; + PointerAlign = 8; + SizeType = UnsignedInt; + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + IntPtrType = SignedShort; + 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:16:8:8-i8:8:8-i16:8:8-i32:8:8-f32:32:32"; + + } + virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return 16; } + virtual uint64_t getPointerAlignV(unsigned AddrSpace) const { return 8; } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + Define(Defines, "__pic16"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const {} + virtual const char *getVAListDeclaration() const { return "";} + virtual const char *getClobbers() const {return "";} + virtual const char *getTargetPrefix() const {return "pic16";} + 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; + LongWidth = LongLongWidth = 32; + IntMaxTWidth = 32; + PointerWidth = 16; + IntAlign = 8; + LongAlign = LongLongAlign = 8; + PointerAlign = 8; + SizeType = UnsignedInt; + IntMaxType = SignedLong; + UIntMaxType = UnsignedLong; + IntPtrType = SignedShort; + PtrDiffType = SignedInt; + DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8"; + } + virtual void getTargetDefines(const LangOptions &Opts, + std::vector<char> &Defines) const { + Define(Defines, "MSP430"); + Define(Defines, "__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 const char *getTargetPrefix() const { + return "msp430"; + } + 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 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); + } +} + + +//===----------------------------------------------------------------------===// +// Driver code +//===----------------------------------------------------------------------===// + +static inline bool IsX86(const std::string& TT) { + return (TT.size() >= 5 && TT[0] == 'i' && TT[2] == '8' && TT[3] == '6' && + TT[4] == '-' && TT[1] - '3' < 6); +} + +/// CreateTargetInfo - Return the target info object for the specified target +/// triple. +TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) { + // OS detection; this isn't really anywhere near complete. + // Additions and corrections are welcome. + bool isDarwin = T.find("-darwin") != std::string::npos; + bool isDragonFly = T.find("-dragonfly") != std::string::npos; + bool isFreeBSD = T.find("-freebsd") != std::string::npos; + bool isSolaris = T.find("-solaris") != std::string::npos; + bool isLinux = T.find("-linux") != std::string::npos; + bool isWindows = T.find("-windows") != std::string::npos || + T.find("-win32") != std::string::npos || + T.find("-mingw") != std::string::npos; + + if (T.find("ppc-") == 0 || T.find("powerpc-") == 0) { + if (isDarwin) + return new DarwinPPCTargetInfo(T); + return new PPC32TargetInfo(T); + } + + if (T.find("ppc64-") == 0 || T.find("powerpc64-") == 0) { + if (isDarwin) + return new DarwinPPC64TargetInfo(T); + return new PPC64TargetInfo(T); + } + + if (T.find("armv") == 0 || T.find("arm-") == 0 || T.find("xscale") == 0) { + if (isDarwin) + return new DarwinARMTargetInfo(T); + if (isFreeBSD) + return new FreeBSDARMTargetInfo(T); + return new ARMTargetInfo(T); + } + + if (T.find("sparc-") == 0) { + if (isSolaris) + return new SolarisSparcV8TargetInfo(T); + return new SparcV8TargetInfo(T); + } + + if (T.find("x86_64-") == 0 || T.find("amd64-") == 0) { + if (isDarwin) + return new DarwinX86_64TargetInfo(T); + if (isLinux) + return new LinuxX86_64TargetInfo(T); + if (isFreeBSD) + return new FreeBSDX86_64TargetInfo(T); + if (isSolaris) + return new SolarisX86_64TargetInfo(T); + return new X86_64TargetInfo(T); + } + + if (T.find("pic16-") == 0) + return new PIC16TargetInfo(T); + + if (T.find("msp430-") == 0) + return new MSP430TargetInfo(T); + + if (IsX86(T)) { + if (isDarwin) + return new DarwinI386TargetInfo(T); + if (isLinux) + return new LinuxX86_32TargetInfo(T); + if (isDragonFly) + return new DragonFlyX86_32TargetInfo(T); + if (isFreeBSD) + return new FreeBSDX86_32TargetInfo(T); + if (isSolaris) + return new SolarisX86_32TargetInfo(T); + if (isWindows) + return new WindowsX86_32TargetInfo(T); + return new X86_32TargetInfo(T); + } + + return NULL; +} diff --git a/lib/Basic/TokenKinds.cpp b/lib/Basic/TokenKinds.cpp new file mode 100644 index 0000000..4afeaf0 --- /dev/null +++ b/lib/Basic/TokenKinds.cpp @@ -0,0 +1,90 @@ +//===--- 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) { + case tok::l_square: return "["; + case tok::r_square: return "]"; + case tok::l_paren: return "("; + case tok::r_paren: return ")"; + case tok::l_brace: return "{"; + case tok::r_brace: return "}"; + case tok::period: return "."; + case tok::ellipsis: return "..."; + case tok::amp: return "&"; + case tok::ampamp: return "&&"; + case tok::ampequal: return "&="; + case tok::star: return "*"; + case tok::starequal: return "*="; + case tok::plus: return "+"; + case tok::plusplus: return "++"; + case tok::plusequal: return "+="; + case tok::minus: return "-"; + case tok::arrow: return "->"; + case tok::minusminus: return "--"; + case tok::minusequal: return "-="; + case tok::tilde: return "~"; + case tok::exclaim: return "!"; + case tok::exclaimequal: return "!="; + case tok::slash: return "/"; + case tok::slashequal: return "/="; + case tok::percent: return "%"; + case tok::percentequal: return "%="; + case tok::less: return "<"; + case tok::lessless: return "<<"; + case tok::lessequal: return "<="; + case tok::lesslessequal: return "<<="; + case tok::greater: return ">"; + case tok::greatergreater: return ">>"; + case tok::greaterequal: return ">="; + case tok::greatergreaterequal: return ">>="; + case tok::caret: return "^"; + case tok::caretequal: return "^="; + case tok::pipe: return "|"; + case tok::pipepipe: return "||"; + case tok::pipeequal: return "|="; + case tok::question: return "?"; + case tok::colon: return ":"; + case tok::semi: return ";"; + case tok::equal: return "="; + case tok::equalequal: return "=="; + case tok::comma: return ","; + case tok::hash: return "#"; + case tok::hashhash: return "##"; + case tok::hashat: return "#@"; + case tok::periodstar: return ".*"; + case tok::arrowstar: return "->*"; + case tok::coloncolon: return "::"; + case tok::at: return "@"; + default: break; + } + + return 0; +} |