diff options
92 files changed, 3306 insertions, 1884 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ca44b8..45f3d0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,3 +54,4 @@ add_subdirectory(lib) add_subdirectory(tools) # TODO: docs. +add_subdirectory(test)
\ No newline at end of file diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 9cb1c5f..b9b966e 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 03F50AC60D416EAA00B9CF60 /* Targets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 03F50AC50D416EAA00B9CF60 /* Targets.cpp */; }; + 1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A14D3A60FD78A3F00DA2835 /* DeclPrinter.cpp */; }; 1A2193CE0F45EEB700C0713D /* Mangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2193CC0F45EEB700C0713D /* Mangle.cpp */; }; 1A2A54B50FD1DD1C00F4CE45 /* AnalysisConsumer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A40FD1DD1C00F4CE45 /* AnalysisConsumer.cpp */; }; 1A2A54B60FD1DD1C00F4CE45 /* ASTConsumers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2A54A50FD1DD1C00F4CE45 /* ASTConsumers.cpp */; }; @@ -105,6 +106,7 @@ 84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */; }; 84D9A88C0C1A581300AC7ABC /* AttributeList.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84D9A88B0C1A581300AC7ABC /* AttributeList.h */; }; 906BF4B00F83BA2E001071FA /* ConvertUTF.c in Sources */ = {isa = PBXBuildFile; fileRef = 906BF4AF0F83BA2E001071FA /* ConvertUTF.c */; }; + BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */; }; DE01DA490B12ADA300AC22CE /* PPCallbacks.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE01DA480B12ADA300AC22CE /* PPCallbacks.h */; }; DE06756C0C051CFE00EBBFD8 /* ParseExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */; }; DE06B73E0A8307640050E87E /* LangOptions.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE06B73D0A8307640050E87E /* LangOptions.h */; }; @@ -321,6 +323,7 @@ /* Begin PBXFileReference section */ 035611470DA6A45C00D2EF2A /* DeclBase.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclBase.h; path = clang/AST/DeclBase.h; sourceTree = "<group>"; tabWidth = 2; }; 03F50AC50D416EAA00B9CF60 /* Targets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Targets.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1A14D3A60FD78A3F00DA2835 /* DeclPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclPrinter.cpp; path = lib/AST/DeclPrinter.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A2193CB0F45EEB700C0713D /* ABIInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ABIInfo.h; path = lib/CodeGen/ABIInfo.h; sourceTree = "<group>"; tabWidth = 2; }; 1A2193CC0F45EEB700C0713D /* Mangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Mangle.cpp; path = lib/CodeGen/Mangle.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A2193CD0F45EEB700C0713D /* Mangle.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Mangle.h; path = lib/CodeGen/Mangle.h; sourceTree = "<group>"; tabWidth = 2; }; @@ -346,14 +349,14 @@ 1A376A2C0D4AED9B002A1C52 /* CGExprConstant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGExprConstant.cpp; path = lib/CodeGen/CGExprConstant.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A410F840FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateExpr.cpp; path = lib/Sema/SemaTemplateInstantiateExpr.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBlocks.cpp; path = lib/CodeGen/CGBlocks.cpp; sourceTree = "<group>"; tabWidth = 2; }; - 1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateStmt.cpp; path = lib/Sema/SemaTemplateInstantiateStmt.cpp; sourceTree = "<group>"; }; + 1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateStmt.cpp; path = lib/Sema/SemaTemplateInstantiateStmt.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A5D5E570E5E81010023C059 /* CGCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXX.cpp; path = lib/CodeGen/CGCXX.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A649E1D0F9599D9005B965E /* CGBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGBlocks.h; path = lib/CodeGen/CGBlocks.h; sourceTree = "<group>"; }; 1A649E1E0F9599DA005B965E /* CGCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGCXX.h; path = lib/CodeGen/CGCXX.h; sourceTree = "<group>"; }; 1A68BC110D0CADDD001A28C8 /* PPCBuiltins.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = PPCBuiltins.def; path = clang/AST/PPCBuiltins.def; sourceTree = "<group>"; tabWidth = 2; }; 1A68BC120D0CADDD001A28C8 /* TargetBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TargetBuiltins.h; path = clang/AST/TargetBuiltins.h; sourceTree = "<group>"; tabWidth = 2; }; 1A68BC130D0CADDD001A28C8 /* X86Builtins.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = X86Builtins.def; path = clang/AST/X86Builtins.def; sourceTree = "<group>"; tabWidth = 2; }; - 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXTemp.cpp; path = lib/CodeGen/CGCXXTemp.cpp; sourceTree = "<group>"; }; + 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXTemp.cpp; path = lib/CodeGen/CGCXXTemp.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1A7019E90F79BC1100FEC4D1 /* DiagnosticAnalysisKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticAnalysisKinds.td; sourceTree = "<group>"; }; 1A7019EA0F79BC1100FEC4D1 /* DiagnosticASTKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticASTKinds.td; sourceTree = "<group>"; }; 1A7019EB0F79BC1100FEC4D1 /* DiagnosticCommonKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticCommonKinds.td; sourceTree = "<group>"; }; @@ -489,6 +492,7 @@ 90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclContextInternals.h; path = clang/AST/DeclContextInternals.h; sourceTree = "<group>"; }; 90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclVisitor.h; path = clang/AST/DeclVisitor.h; sourceTree = "<group>"; }; 90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalASTSource.h; path = clang/AST/ExternalASTSource.h; sourceTree = "<group>"; }; + BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateDeduction.cpp; path = lib/Sema/SemaTemplateDeduction.cpp; sourceTree = "<group>"; tabWidth = 2; }; DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = "<group>"; }; DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = lib/Parse/ParseExprCXX.cpp; sourceTree = "<group>"; tabWidth = 2; }; DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = "<group>"; tabWidth = 2; }; @@ -595,7 +599,7 @@ DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MultipleIncludeOpt.h; sourceTree = "<group>"; }; DEAEED4A0A5AF89A0045101B /* NOTES.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = NOTES.txt; sourceTree = "<group>"; }; DEB076C90F3A221200F5A2BE /* DeclTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclTemplate.h; path = clang/AST/DeclTemplate.h; sourceTree = "<group>"; tabWidth = 2; }; - DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclTemplate.cpp; path = lib/AST/DeclTemplate.cpp; sourceTree = "<group>"; }; + DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclTemplate.cpp; path = lib/AST/DeclTemplate.cpp; sourceTree = "<group>"; tabWidth = 2; }; DEB077930F44F96000F5A2BE /* TokenConcatenation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TokenConcatenation.h; sourceTree = "<group>"; }; DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenConcatenation.cpp; sourceTree = "<group>"; }; DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAttr.cpp; path = lib/Sema/SemaAttr.cpp; sourceTree = "<group>"; tabWidth = 2; }; @@ -605,7 +609,7 @@ DEC8D9900A9433CD00353FCA /* Decl.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Decl.h; path = clang/AST/Decl.h; sourceTree = "<group>"; tabWidth = 2; }; DEC8D9A30A94346E00353FCA /* AST.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AST.h; path = clang/AST/AST.h; sourceTree = "<group>"; tabWidth = 2; }; DECAB0CF0DB3C84200E13CCB /* RewriteRope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteRope.cpp; path = lib/Rewrite/RewriteRope.cpp; sourceTree = "<group>"; }; - DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JumpDiagnostics.cpp; path = lib/Sema/JumpDiagnostics.cpp; sourceTree = "<group>"; }; + DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = JumpDiagnostics.cpp; path = lib/Sema/JumpDiagnostics.cpp; sourceTree = "<group>"; tabWidth = 2; }; DECB6F030F9D939A00F5FBC7 /* InitPreprocessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InitPreprocessor.h; path = clang/Frontend/InitPreprocessor.h; sourceTree = "<group>"; }; DECB6F060F9D93A800F5FBC7 /* InitPreprocessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitPreprocessor.cpp; path = lib/Frontend/InitPreprocessor.cpp; sourceTree = "<group>"; }; DECB734E0FA3ED8400F5FBC7 /* StmtObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StmtObjC.h; path = clang/AST/StmtObjC.h; sourceTree = "<group>"; }; @@ -1063,6 +1067,7 @@ 35585DBF0EAFBC4500D0A97A /* SemaOverload.h */, DE67E70C0C020ECA00F66BC5 /* SemaStmt.cpp */, 3591853E0EFB1088000039AF /* SemaTemplate.cpp */, + BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */, 35544B8B0F5C803200D92AA9 /* SemaTemplateInstantiate.cpp */, 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */, 1A410F840FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp */, @@ -1193,6 +1198,7 @@ 3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */, 35EE48AF0E0C4CCA00715C54 /* DeclCXX.cpp */, 358D230A0E8BEB9D0003DDCC /* DeclGroup.cpp */, + 1A14D3A60FD78A3F00DA2835 /* DeclPrinter.cpp */, DE38CF260D8C9E6C00A273B6 /* DeclObjC.cpp */, DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */, DE0FCB330A9C21F100248FD5 /* Expr.cpp */, @@ -1691,6 +1697,8 @@ 1A2A54C40FD1DD1C00F4CE45 /* StmtXML.cpp in Sources */, 1A2A54C50FD1DD1C00F4CE45 /* Warnings.cpp in Sources */, 1A6FE7090FD6F85800E00CA9 /* CGCXXTemp.cpp in Sources */, + BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */, + 1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/docs/PCHInternals.html b/docs/PCHInternals.html index 7c0c140..6ea1692 100644 --- a/docs/PCHInternals.html +++ b/docs/PCHInternals.html @@ -1,6 +1,13 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> <head> -<title>Precompiled Headers (PCH)</title> +<html> +<head> + <title>Precompiled Headers (PCH)</title> + <link type="text/css" rel="stylesheet" href="../menu.css" /> + <link type="text/css" rel="stylesheet" href="../content.css" /> + <style type="text/css"> + td { + vertical-align: top; + } + </style> </head> <body> @@ -33,7 +40,9 @@ <li><a href="#method-pool">Method Pool Block</a></li> </ul> </li> - </ul> + <li><a href="#tendrils">Precompiled Header Integration + Points</a></li> +</ul> <h2 id="usage">Using Precompiled Headers with <tt>clang-cc</tt></h2> @@ -103,7 +112,37 @@ entity (and those entities it depends on) are deserialized from the PCH file. With this approach, the cost of using a precompiled header for a translation unit is proportional to the amount of code actually used from the header, rather than being proportional to the size of -the header itself.</p> </body> +the header itself.</p> + +<p>When given the <code>-print-stats</code> option, Clang produces +statistics describing how much of the precompiled header was actually +loaded from disk. For a simple "Hello, World!" program that includes +the Apple <code>Cocoa.h</code> header (which is built as a precompiled +header), this option illustrates how little of the actual precompiled +header is required:</p> + +<pre> +*** PCH Statistics: + 933 stat cache hits + 4 stat cache misses + 895/39981 source location entries read (2.238563%) + 19/15315 types read (0.124061%) + 20/82685 declarations read (0.024188%) + 154/58070 identifiers read (0.265197%) + 0/7260 selectors read (0.000000%) + 0/30842 statements read (0.000000%) + 4/8400 macros read (0.047619%) + 1/4995 lexical declcontexts read (0.020020%) + 0/4413 visible declcontexts read (0.000000%) + 0/7230 method pool entries read (0.000000%) + 0 method pool misses +</pre> + +<p>For this small program, only a tiny fraction of the source +locations, types, declarations, identifiers, and macros were actually +deserialized from the precompiled header. These statistics can be +useful to determine whether the precompiled header implementation can +be improved by making more of the implementation lazy.</p> <h2 id="contents">Precompiled Header Contents</h2> @@ -117,6 +156,14 @@ either a block or a record within <a format</a>. The contents of each of these logical blocks are described below.</p> +<p>For a given precompiled header, the <a +href="http://llvm.org/cmds/llvm-bcanalyzer.html"><code>llvm-bcanalyzer</code></a> +utility can be used to examine the actual structure of the bitstream +for the precompiled header. This information can be used both to help +understand the structure of the precompiled header and to isolate +areas where precompiled headers can still be optimized, e.g., through +the introduction of abbreviations.</p> + <h3 id="metadata">Metadata Block</h3> <p>The metadata block contains several records that provide @@ -393,7 +440,60 @@ values to the offset of the selector within the on-disk hash table, and will be used when de-serializing an Objective-C method declaration (or other Objective-C construct) that refers to the selector.</p> -<h2 id="tendrils"></h2> +<h2 id="tendrils">Precompiled Header Integration Points</h2> + +<p>The "lazy" deserialization behavior of precompiled headers requires +their integration into several completely different submodules of +Clang. For example, lazily deserializing the declarations during name +lookup requires that the name-lookup routines be able to query the +precompiled header to find entities within the PCH file.</p> + +<p>For each Clang data structure that requires direct interaction with +the precompiled header logic, there is an abstract class that provides +the interface between the two modules. The <code>PCHReader</code> +class, which handles the loading of a precompiled header, inherits +from all of these abstract classes to provide lazy deserialization of +Clang's data structures. <code>PCHReader</code> implements the +following abstract classes:</p> + +<dl> + <dt><code>StatSysCallCache</code></dt> + <dd>This abstract interface is associated with the + <code>FileManager</code> class, and is used whenever the file + manager is going to perform a <code>stat()</code> system call.</dd> + + <dt><code>ExternalSLocEntrySource</code></dt> + <dd>This abstract interface is associated with the + <code>SourceManager</code> class, and is used whenever the + <a href="#sourcemgr">source manager</a> needs to load the details + of a file, buffer, or macro instantiation.</dd> + + <dt><code>IdentifierInfoLookup</code></dt> + <dd>This abstract interface is associated with the + <code>IdentifierTable</code> class, and is used whenever the + program source refers to an identifier that has not yet been seen. + In this case, the precompiled header implementation searches for + this identifier within its <a href="#idtable">identifier table</a> + to load any top-level declarations or macros associated with that + identifier.</dd> + + <dt><code>ExternalASTSource</code></dt> + <dd>This abstract interface is associated with the + <code>ASTContext</code> class, and is used whenever the abstract + syntax tree nodes need to loaded from the precompiled header. It + provides the ability to de-serialize declarations and types + identified by their numeric values, read the bodies of functions + when required, and read the declarations stored within a + declaration context (either for iteration or for name lookup).</dd> + + <dt><code>ExternalSemaSource</code></dt> + <dd>This abstract interface is associated with the <code>Sema</code> + class, and is used whenever semantic analysis needs to read + information from the <a href="#methodpool">global method + pool</a>.</dd> +</dl> + </div> +</body> </html> diff --git a/docs/UsersManual.html b/docs/UsersManual.html index 3f48c4abe..e7072da 100644 --- a/docs/UsersManual.html +++ b/docs/UsersManual.html @@ -431,50 +431,43 @@ headers vary between compilers, precompiled headers have been shown to be a highly effective at speeding up program compilation on systems with very large system headers (e.g., Mac OS/X).</p> -<p>Clang supports an implementation of precompiled headers known as -<em>pre-tokenized headers</em> (PTH). Clang's pre-tokenized headers support most -of same interfaces as GCC's pre-compiled headers (as well as others) but are -completely different in their implementation. If you are interested in how -PTH is implemented, please see the <a href="PTHInternals.html">PTH Internals - document</a>.</p> +<h4>Generating a PCH File</h4> -<h4>Generating a PTH File</h4> - -<p>To generate a PTH file using Clang, one invokes Clang with +<p>To generate a PCH file using Clang, one invokes Clang with the <b><tt>-x <i><language></i>-header</tt></b> option. This mirrors the interface in GCC for generating PCH files:</p> <pre> $ gcc -x c-header test.h -o test.h.gch - $ clang -x c-header test.h -o test.h.pth + $ clang -x c-header test.h -o test.h.pch </pre> -<h4>Using a PTH File</h4> +<h4>Using a PCH File</h4> -<p>A PTH file can then be used as a prefix header when a +<p>A PCH file can then be used as a prefix header when a <b><tt>-include</tt></b> option is passed to <tt>clang</tt>:</p> <pre> $ clang -include test.h test.c -o test </pre> -<p>The <tt>clang</tt> driver will first check if a PTH file for <tt>test.h</tt> +<p>The <tt>clang</tt> driver will first check if a PCH file for <tt>test.h</tt> is available; if so, the contents of <tt>test.h</tt> (and the files it includes) -will be processed from the PTH file. Otherwise, Clang falls back to +will be processed from the PCH file. Otherwise, Clang falls back to directly processing the content of <tt>test.h</tt>. This mirrors the behavior of GCC.</p> -<p><b>NOTE:</b> Clang does <em>not</em> automatically use PTH files +<p><b>NOTE:</b> Clang does <em>not</em> automatically use PCH files for headers that are directly included within a source file. For example:</p> <pre> - $ clang -x c-header test.h -o test.h.pth + $ clang -x c-header test.h -o test.h.cth $ cat test.c #include "test.h" $ clang test.c -o test </pre> -<p>In this example, <tt>clang</tt> will not automatically use the PTH file for +<p>In this example, <tt>clang</tt> will not automatically use the PCH file for <tt>test.h</tt> since <tt>test.h</tt> was included directly in the source file and not specified on the command line using <tt>-include</tt>.</p> @@ -607,6 +600,12 @@ in structures. This is for a few of reasons: one, it is tricky to implement, two, the extension is completely undocumented, and three, the extension appears to be very rarely used.</p> +<p>clang does not support duplicate definitions of a function where one is +inline. This complicates clients of the AST which normally can expect there is +at most one definition for each function. Source code using this feature should +be changed to define the inline and out-of-line definitions in separate +translation units.</p> + <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = --> <h3 id="c_ms">Microsoft extensions</h3> <!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = --> diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index e99e9f2..cad5487 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -539,11 +539,16 @@ public: void CollectObjCIvars(const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl<FieldDecl*> &Fields); - + + void ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars, + bool CollectSynthesized = true); void CollectSynthesizedIvars(const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); void CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD, llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); + unsigned CountSynthesizedIvars(const ObjCInterfaceDecl *OI); + unsigned CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD); //===--------------------------------------------------------------------===// // Type Operators diff --git a/include/clang/AST/Builtins.def b/include/clang/AST/Builtins.def index 11f3264..c2f4061 100644 --- a/include/clang/AST/Builtins.def +++ b/include/clang/AST/Builtins.def @@ -332,25 +332,31 @@ BUILTIN(__sync_fetch_and_max, "ii*i", "n") BUILTIN(__sync_fetch_and_umin, "UiUi*Ui", "n") BUILTIN(__sync_fetch_and_umax, "UiUi*Ui", "n") -// Builtin library functions -LIBBUILTIN(alloca, "v*z", "f", "stdlib.h") +// C99 library functions +// C99 stdlib.h LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h") LIBBUILTIN(malloc, "v*z", "f", "stdlib.h") LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h") +// C99 string.h LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h") LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h") -LIBBUILTIN(memset, "v*v*iz", "f", "string.h") +LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h") +LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h") LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h") +LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h") +LIBBUILTIN(strxfrm, "zc*cC*z", "f", "string.h") +LIBBUILTIN(memchr, "v*vC*iz", "f", "string.h") LIBBUILTIN(strchr, "c*cC*i", "f", "string.h") -LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h") LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h") -LIBBUILTIN(strlen, "zcC*", "f", "string.h") -LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h") -LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h") LIBBUILTIN(strpbrk, "c*cC*cC*", "f", "string.h") LIBBUILTIN(strrchr, "c*cC*i", "f", "string.h") LIBBUILTIN(strspn, "zcC*cC*", "f", "string.h") LIBBUILTIN(strstr, "c*cC*cC*", "f", "string.h") +LIBBUILTIN(strtok, "c*c*cC*", "f", "string.h") +LIBBUILTIN(memset, "v*v*iz", "f", "string.h") +LIBBUILTIN(strerror, "c*i", "f", "string.h") +LIBBUILTIN(strlen, "zcC*", "f", "string.h") +// C99 stdio.h LIBBUILTIN(printf, "icC*.", "fp:0:", "stdio.h") LIBBUILTIN(fprintf, "iP*cC*.", "fp:1:", "stdio.h") LIBBUILTIN(snprintf, "ic*zcC*.", "fp:2:", "stdio.h") @@ -360,6 +366,18 @@ LIBBUILTIN(vfprintf, "i.", "fP:1:", "stdio.h") LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h") LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h") +// Non-C library functions +// FIXME: Non-C-standard stuff shouldn't be builtins in non-GNU mode! +LIBBUILTIN(alloca, "v*z", "f", "stdlib.h") +// POSIX string.h +LIBBUILTIN(stpcpy, "c*c*cC*", "f", "string.h") +LIBBUILTIN(stpncpy, "c*c*cC*z", "f", "string.h") +LIBBUILTIN(strdup, "c*cC*", "f", "string.h") +LIBBUILTIN(strndup, "c*cC*z", "f", "string.h") +// POSIX strings.h +LIBBUILTIN(index, "c*cC*i", "f", "strings.h") +LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h") + // FIXME: This type isn't very correct, it should be // id objc_msgSend(id, SEL) // but we need new type letters for that. diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index e134aed..7440e7b 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -515,10 +515,22 @@ public: objcDeclQualifier = QTVal; } - const Expr *getDefaultArg() const { return DefaultArg; } - Expr *getDefaultArg() { return DefaultArg; } + const Expr *getDefaultArg() const { + assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); + return DefaultArg; + } + Expr *getDefaultArg() { + assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); + return DefaultArg; + } void setDefaultArg(Expr *defarg) { DefaultArg = defarg; } + /// hasDefaultArg - Determines whether this parameter has a default argument, + /// either parsed or not. + bool hasDefaultArg() const { + return DefaultArg != 0; + } + /// hasUnparsedDefaultArg - Determines whether this parameter has a /// default argument that has not yet been parsed. This will occur /// during the processing of a C++ class whose member functions have diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 6e89a7a..3943ddc 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -330,6 +330,7 @@ public: // Get the local instance/class method declared in this interface. ObjCMethodDecl *getInstanceMethod(ASTContext &Context, Selector Sel) const; ObjCMethodDecl *getClassMethod(ASTContext &Context, Selector Sel) const; + ObjCIvarDecl *getIvarDecl(ASTContext &Context, IdentifierInfo *Id) const; ObjCMethodDecl * getMethod(ASTContext &Context, Selector Sel, bool isInstance) const { diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 226af34..d189900 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -203,6 +203,9 @@ public: /// Get the position of the template parameter within its parameter list. unsigned getPosition() const { return Position; } + + /// Get the index of the template parameter within its parameter list. + unsigned getIndex() const { return Position; } }; /// TemplateTypeParmDecl - Declaration of a template type parameter, @@ -299,7 +302,8 @@ public: using TemplateParmPosition::getDepth; using TemplateParmPosition::getPosition; - + using TemplateParmPosition::getIndex; + /// \brief Determine whether this template parameter has a default /// argument. bool hasDefaultArgument() const { return DefaultArgument; } @@ -350,7 +354,8 @@ public: using TemplateParmPosition::getDepth; using TemplateParmPosition::getPosition; - + using TemplateParmPosition::getIndex; + /// \brief Determine whether this template parameter has a default /// argument. bool hasDefaultArgument() const { return DefaultArgument; } @@ -390,20 +395,21 @@ class TemplateArgument { public: /// \brief The type of template argument we're storing. enum ArgKind { + Null = 0, /// The template argument is a type. It's value is stored in the /// TypeOrValue field. - Type = 0, + Type = 1, /// The template argument is a declaration - Declaration = 1, + Declaration = 2, /// The template argument is an integral value stored in an llvm::APSInt. - Integral = 2, + Integral = 3, /// The template argument is a value- or type-dependent expression /// stored in an Expr*. - Expression = 3 + Expression = 4 } Kind; /// \brief Construct an empty, invalid template argument. - TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Type) { } + TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Null) { } /// \brief Construct a template type argument. TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) { @@ -484,6 +490,9 @@ public: /// \brief Return the kind of stored template argument. ArgKind getKind() const { return Kind; } + /// \brief Determine whether this template argument has no value. + bool isNull() const { return Kind == Null; } + /// \brief Retrieve the template argument as a type. QualType getAsType() const { if (Kind != Type) @@ -519,6 +528,12 @@ public: return QualType::getFromOpaquePtr(Integer.Type); } + void setIntegralType(QualType T) { + assert(Kind == Integral && + "Cannot set the integral type of a non-integral template argument"); + Integer.Type = T.getAsOpaquePtr(); + }; + /// \brief Retrieve the template argument as an expression. Expr *getAsExpr() const { if (Kind != Expression) @@ -534,6 +549,9 @@ public: void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Kind); switch (Kind) { + case Null: + break; + case Type: getAsType().Profile(ID); break; @@ -555,6 +573,22 @@ public: } }; +/// \brief A helper class for making template argument lists. +class TemplateArgumentListBuilder { + llvm::SmallVector<TemplateArgument, 16> Args; + + ASTContext &Context; +public: + TemplateArgumentListBuilder(ASTContext &Context) : Context(Context) { } + + // FIXME: Should use the index array size. + size_t size() const { return Args.size(); } + size_t flatSize() const { return Args.size(); } + + void push_back(const TemplateArgument& Arg); + TemplateArgument *getFlatArgumentList() { return Args.data(); } +}; + /// \brief A template argument list. /// /// FIXME: In the future, this class will be extended to support @@ -571,12 +605,10 @@ class TemplateArgumentList { /// argument list. unsigned NumArguments; - public: TemplateArgumentList(ASTContext &Context, - TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, - bool CopyArgs); + TemplateArgumentListBuilder &Builder, + bool CopyArgs, bool FlattenArgs); ~TemplateArgumentList(); @@ -660,14 +692,13 @@ protected: ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, - TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs); + TemplateArgumentListBuilder &Builder); public: static ClassTemplateSpecializationDecl * Create(ASTContext &Context, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, - TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + TemplateArgumentListBuilder &Builder, ClassTemplateSpecializationDecl *PrevDecl); /// \brief Retrieve the template that this specialization specializes. @@ -730,11 +761,9 @@ class ClassTemplatePartialSpecializationDecl DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, - TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs) + TemplateArgumentListBuilder &Builder) : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization, - DC, L, SpecializedTemplate, TemplateArgs, - NumTemplateArgs), + DC, L, SpecializedTemplate, Builder), TemplateParams(Params) { } public: @@ -742,7 +771,7 @@ public: Create(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, - TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + TemplateArgumentListBuilder &Builder, ClassTemplatePartialSpecializationDecl *PrevDecl); /// Get the list of template parameters diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 5338623..e44ccca 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1023,14 +1023,17 @@ class CXXExprWithTemporaries : public Expr { CXXTemporary **Temps; unsigned NumTemps; - CXXExprWithTemporaries(Expr *subexpr, CXXTemporary **temps, - unsigned numtemps); + bool DestroyTemps; + + CXXExprWithTemporaries(Expr *SubExpr, CXXTemporary **Temps, + unsigned NumTemps, bool DestroyTemps); ~CXXExprWithTemporaries(); public: static CXXExprWithTemporaries *Create(ASTContext &C, Expr *SubExpr, CXXTemporary **Temps, - unsigned NumTemps); + unsigned NumTemps, + bool DestroyTems); void Destroy(ASTContext &C); unsigned getNumTemporaries() const { return NumTemps; } diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 1bc296b..ae5246d 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -130,6 +130,9 @@ def warn_pch_compiler_options_mismatch : Error< def warn_pch_access_control : Error< "C++ access control was %select{disabled|enabled}0 in the PCH file but " "is currently %select{disabled|enabled}1">; +def warn_pch_char_signed : Error< + "char was %select{unsigned|signed}0 in the PCH file but " + "is currently %select{unsigned|signed}1">; def err_not_a_pch_file : Error< "'%0' does not appear to be a precompiled header file">, DefaultFatal; diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 2912344..81afac9 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -264,6 +264,8 @@ def warn_pragma_expected_rparen : Warning< "missing ')' after '#pragma %0' - ignoring">; def warn_pragma_expected_identifier : Warning< "expected identifier in '#pragma %0' - ignored">; +def warn_pragma_extra_tokens_at_eol : Warning< + "extra tokens at end of '#pragma %0' - ignored">; // - #pragma pack def warn_pragma_pack_invalid_action : Warning< "unknown action for '#pragma pack' - ignored">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 41e73c1..4b9b703 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -131,6 +131,8 @@ def warn_pragma_pack_pop_failed : Warning<"#pragma pack(pop, ...) failed: %0">; def warn_pragma_unused_expected_localvar : Warning< "only local variables can be arguments to '#pragma unused'">; +def err_unsupported_pragma_weak : Error< + "using '#pragma weak' to refer to an undeclared identifier is not yet supported">; /// Objective-C parser diagnostics def err_duplicate_class_def : Error< diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 92370cd..7c578e3 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -79,6 +79,7 @@ public: unsigned AccessControl : 1; // Whether C++ access control should // be enabled. + unsigned CharIsSigned : 1; // Whether char is a signed or unsigned type private: unsigned GC : 2; // Objective-C Garbage Collection modes. We declare // this enum as unsigned because MSVC insists on making enums @@ -137,6 +138,8 @@ public: GNUInline = 0; NoInline = 0; + CharIsSigned = 1; + MainFileName = 0; } diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index f577d6b..a59c60b 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -38,7 +38,6 @@ class TargetInfo { protected: // Target values set by the ctor of the actual target implementation. Default // values are specified by the TargetInfo constructor. - bool CharIsSigned; bool TLSSupported; unsigned char PointerWidth, PointerAlign; unsigned char WCharWidth, WCharAlign; @@ -88,11 +87,6 @@ public: IntType getIntPtrType() const { return IntPtrType; } IntType getWCharType() const { return WCharType; } - /// isCharSigned - Return true if 'char' is 'signed char' or false if it is - /// treated as 'unsigned char'. This is implementation defined according to - /// C99 6.2.5p15. In our implementation, this is target-specific. - bool isCharSigned() const { return CharIsSigned; } - /// getPointerWidth - Return the width of pointers on this target, for the /// specified address space. uint64_t getPointerWidth(unsigned AddrSpace) const { diff --git a/include/clang/Driver/Options.def b/include/clang/Driver/Options.def index 32b29cd..742a04a 100644 --- a/include/clang/Driver/Options.def +++ b/include/clang/Driver/Options.def @@ -194,6 +194,7 @@ OPTION("--no-integrated-cpp", _no_integrated_cpp, Flag, INVALID, no_integrated_c OPTION("--no-line-commands", _no_line_commands, Flag, INVALID, P, "", 0, 0, 0) OPTION("--no-standard-includes", _no_standard_includes, Flag, INVALID, nostdinc, "", 0, 0, 0) OPTION("--no-standard-libraries", _no_standard_libraries, Flag, INVALID, nostdlib, "", 0, 0, 0) +OPTION("--no-undefined", _no_undefined, Flag, INVALID, INVALID, "l", 0, 0, 0) OPTION("--no-warnings", _no_warnings, Flag, INVALID, w, "", 0, 0, 0) OPTION("--optimize=", _optimize_EQ, Joined, INVALID, O, "u", 0, 0, 0) OPTION("--optimize", _optimize, Flag, INVALID, O, "u", 0, 0, 0) @@ -226,6 +227,7 @@ OPTION("--resource=", _resource_EQ, Joined, INVALID, fcompile_resource_EQ, "", 0 OPTION("--resource", _resource, Separate, INVALID, fcompile_resource_EQ, "J", 0, 0, 0) OPTION("--save-temps", _save_temps, Flag, INVALID, save_temps, "", 0, 0, 0) OPTION("--shared", _shared, Flag, INVALID, shared, "", 0, 0, 0) +OPTION("--signed-char", _signed_char, Flag, INVALID, fsigned_char, "", 0, 0, 0) OPTION("--specs=", _specs_EQ, Joined, INVALID, specs_EQ, "u", 0, 0, 0) OPTION("--specs", _specs, Separate, INVALID, specs_EQ, "uJ", 0, 0, 0) OPTION("--static", _static, Flag, INVALID, static, "", 0, 0, 0) @@ -240,6 +242,7 @@ OPTION("--traditional", _traditional, Flag, INVALID, traditional, "", 0, 0, 0) OPTION("--trigraphs", _trigraphs, Flag, INVALID, trigraphs, "", 0, 0, 0) OPTION("--undefine-macro=", _undefine_macro_EQ, Joined, INVALID, U, "", 0, 0, 0) OPTION("--undefine-macro", _undefine_macro, Separate, INVALID, U, "J", 0, 0, 0) +OPTION("--unsigned-char", _unsigned_char, Flag, INVALID, funsigned_char, "", 0, 0, 0) OPTION("--user-dependencies", _user_dependencies, Flag, INVALID, MM, "", 0, 0, 0) OPTION("--verbose", _verbose, Flag, INVALID, v, "", 0, 0, 0) OPTION("--version", _version, Flag, INVALID, INVALID, "", 0, 0, 0) @@ -364,6 +367,7 @@ OPTION("-fblocks", fblocks, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fbootclasspath=", fbootclasspath_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) OPTION("-fbuiltin", fbuiltin, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fclasspath=", fclasspath_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fcolor-diagnostics", fcolor_diagnostics, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fcommon", fcommon, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fcompile-resource=", fcompile_resource_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) OPTION("-fconstant-cfstrings", fconstant_cfstrings, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) @@ -402,6 +406,7 @@ OPTION("-fno-asynchronous-unwind-tables", fno_asynchronous_unwind_tables, Flag, OPTION("-fno-blocks", fno_blocks, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-builtin", fno_builtin, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-caret-diagnostics", fno_caret_diagnostics, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fno-color-diagnostics", fno_color_diagnostics, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-common", fno_common, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-constant-cfstrings", fno_constant_cfstrings, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fno-diagnostics-fixit-info", fno_diagnostics_fixit_info, Flag, f_Group, INVALID, "", 0, 0, 0) @@ -442,6 +447,7 @@ OPTION("-fprofile-arcs", fprofile_arcs, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fprofile-generate", fprofile_generate, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-framework", framework, Separate, INVALID, INVALID, "l", 0, 0, 0) OPTION("-fsigned-bitfields", fsigned_bitfields, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-fsigned-char", fsigned_char, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fstack-protector", fstack_protector, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) OPTION("-fstrict-aliasing", fstrict_aliasing, Flag, clang_ignored_f_Group, INVALID, "", 0, 0, 0) OPTION("-fsyntax-only", fsyntax_only, Flag, INVALID, INVALID, "d", 0, 0, 0) @@ -452,6 +458,7 @@ OPTION("-ftraditional", ftraditional, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-ftrapv", ftrapv, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-funit-at-a-time", funit_at_a_time, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-funsigned-bitfields", funsigned_bitfields, Flag, f_Group, INVALID, "", 0, 0, 0) +OPTION("-funsigned-char", funsigned_char, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-funwind-tables", funwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fverbose-asm", fverbose_asm, Flag, f_Group, INVALID, "", 0, 0, 0) OPTION("-fvisibility=", fvisibility_EQ, Joined, f_Group, INVALID, "", 0, 0, 0) @@ -569,6 +576,7 @@ OPTION("-pthread", pthread, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-p", p, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-read_only_relocs", read__only__relocs, Separate, INVALID, INVALID, "", 0, 0, 0) OPTION("-remap", remap, Flag, INVALID, INVALID, "", 0, 0, 0) +OPTION("-rpath", rpath, Separate, INVALID, INVALID, "l", 0, 0, 0) OPTION("-r", r, Flag, INVALID, INVALID, "", 0, 0, 0) OPTION("-save-temps", save_temps, Flag, INVALID, INVALID, "d", 0, "Save intermediate compilation results", 0) diff --git a/include/clang/Frontend/CompileOptions.h b/include/clang/Frontend/CompileOptions.h index 34815c8..75dec00 100644 --- a/include/clang/Frontend/CompileOptions.h +++ b/include/clang/Frontend/CompileOptions.h @@ -41,6 +41,8 @@ public: /// should be run through the LLVM Verifier. unsigned TimePasses : 1; /// Set when -ftime-report is enabled. unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled. + unsigned DisableRedZone : 1; /// Set when -mno-red-zone is enabled. + unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled. /// Inlining - The kind of inlining to perform. InliningMethod Inlining; @@ -63,6 +65,8 @@ public: TimePasses = 0; NoCommon = 0; Inlining = NoInlining; + DisableRedZone = 0; + NoImplicitFloat = 0; } }; diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h index 3c9dcb8..f8408bd 100644 --- a/include/clang/Frontend/TextDiagnosticPrinter.h +++ b/include/clang/Frontend/TextDiagnosticPrinter.h @@ -40,6 +40,7 @@ class TextDiagnosticPrinter : public DiagnosticClient { bool PrintDiagnosticOption; bool PrintFixItInfo; unsigned MessageLength; + bool UseColors; public: TextDiagnosticPrinter(llvm::raw_ostream &os, @@ -48,14 +49,16 @@ public: bool printRangeInfo = true, bool printDiagnosticOption = true, bool printFixItInfo = true, - unsigned messageLength = 0) + unsigned messageLength = 0, + bool useColors = false) : OS(os), LangOpts(0), LastCaretDiagnosticWasNote(false), ShowColumn(showColumn), CaretDiagnostics(caretDiagnistics), ShowLocation(showLocation), PrintRangeInfo(printRangeInfo), PrintDiagnosticOption(printDiagnosticOption), PrintFixItInfo(printFixItInfo), - MessageLength(messageLength) {} + MessageLength(messageLength), + UseColors(useColors) {} void setLangOptions(const LangOptions *LO) { LangOpts = LO; diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 5c23f9a..579fe6c 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -417,6 +417,7 @@ public: } virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, + DeclPtrTy IntfDecl, Declarator &D, ExprTy *BitfieldWidth, tok::ObjCKeywordKind visibility) { return DeclPtrTy(); @@ -1750,13 +1751,29 @@ public: return; } - /// ActOnPragmaPack - Called on well formed #pragma pack(...). + /// ActOnPragmaUnused - Called on well formed #pragma unused(...). virtual void ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs, SourceLocation PragmaLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { return; - } + } + + /// ActOnPragmaWeakID - Called on well formed #pragma weak ident. + virtual void ActOnPragmaWeakID(IdentifierInfo* WeakName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc) { + return; + } + + /// ActOnPragmaWeakAlias - Called on well formed #pragma weak ident = ident. + virtual void ActOnPragmaWeakAlias(IdentifierInfo* WeakName, + IdentifierInfo* AliasName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc, + SourceLocation AliasNameLoc) { + return; + } }; /// MinimalAction - Minimal actions are used by light-weight clients of the diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 26e37e2..6218ade 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -81,6 +81,7 @@ class Parser { llvm::OwningPtr<PragmaHandler> PackHandler; llvm::OwningPtr<PragmaHandler> UnusedHandler; + llvm::OwningPtr<PragmaHandler> WeakHandler; /// Whether the '>' token acts as an operator or not. This will be /// true except when we are parsing an expression within a C++ diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index b36d1f3..e6dea7c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -143,7 +143,7 @@ void ASTContext::InitBuiltinTypes() { // C99 6.2.5p2. InitBuiltinType(BoolTy, BuiltinType::Bool); // C99 6.2.5p3. - if (Target.isCharSigned()) + if (LangOpts.CharIsSigned) InitBuiltinType(CharTy, BuiltinType::Char_S); else InitBuiltinType(CharTy, BuiltinType::Char_U); @@ -613,6 +613,20 @@ void ASTContext::CollectObjCIvars(const ObjCInterfaceDecl *OI, CollectLocalObjCIvars(this, OI, Fields); } +/// ShallowCollectObjCIvars - +/// Collect all ivars, including those synthesized, in the current class. +/// +void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars, + bool CollectSynthesized) { + for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(), + E = OI->ivar_end(); I != E; ++I) { + Ivars.push_back(*I); + } + if (CollectSynthesized) + CollectSynthesizedIvars(OI, Ivars); +} + void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD, llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) { for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(*this), @@ -645,6 +659,38 @@ void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI, } } +unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) { + unsigned count = 0; + for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(*this), + E = PD->prop_end(*this); I != E; ++I) + if ((*I)->getPropertyIvarDecl()) + ++count; + + // Also look into nested protocols. + for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(), + E = PD->protocol_end(); P != E; ++P) + count += CountProtocolSynthesizedIvars(*P); + return count; +} + +unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) +{ + unsigned count = 0; + for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(*this), + E = OI->prop_end(*this); I != E; ++I) { + if ((*I)->getPropertyIvarDecl()) + ++count; + } + // Also look into interface's protocol list for properties declared + // in the protocol and whose ivars are synthesized. + for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(), + PE = OI->protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *PD = (*P); + count += CountProtocolSynthesizedIvars(PD); + } + return count; +} + /// getInterfaceLayoutImpl - Get or compute information about the /// layout of the given interface. /// @@ -664,14 +710,13 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, unsigned FieldCount = D->ivar_size(); // Add in synthesized ivar count if laying out an implementation. if (Impl) { - llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; - CollectSynthesizedIvars(D, Ivars); - FieldCount += Ivars.size(); + unsigned SynthCount = CountSynthesizedIvars(D); + FieldCount += SynthCount; // If there aren't any sythesized ivars then reuse the interface // entry. Note we can't cache this because we simply free all // entries later; however we shouldn't look up implementations // frequently. - if (FieldCount == D->ivar_size()) + if (SynthCount == 0) return getObjCLayout(D, 0); } @@ -701,20 +746,11 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, // Layout each ivar sequentially. unsigned i = 0; - for (ObjCInterfaceDecl::ivar_iterator IVI = D->ivar_begin(), - IVE = D->ivar_end(); IVI != IVE; ++IVI) { - const ObjCIvarDecl* Ivar = (*IVI); - NewEntry->LayoutField(Ivar, i++, false, StructPacking, *this); - } - // And synthesized ivars, if this is an implementation. - if (Impl) { - // FIXME. Do we need to colltect twice? - llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; - CollectSynthesizedIvars(D, Ivars); - for (unsigned k = 0, e = Ivars.size(); k != e; ++k) - NewEntry->LayoutField(Ivars[k], i++, false, StructPacking, *this); - } - + llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; + ShallowCollectObjCIvars(D, Ivars, Impl); + for (unsigned k = 0, e = Ivars.size(); k != e; ++k) + NewEntry->LayoutField(Ivars[k], i++, false, StructPacking, *this); + // Finally, round the size of the total struct up to the alignment of the // struct itself. NewEntry->FinalizeLayout(); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index cb3ec1f..dfec106 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -489,7 +489,7 @@ void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned FunctionDecl::getMinRequiredArguments() const { unsigned NumRequiredArgs = getNumParams(); while (NumRequiredArgs > 0 - && getParamDecl(NumRequiredArgs-1)->getDefaultArg()) + && getParamDecl(NumRequiredArgs-1)->hasDefaultArg()) --NumRequiredArgs; return NumRequiredArgs; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 19f8958..94daf48 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -326,7 +326,7 @@ CXXConstructorDecl::isCopyConstructor(ASTContext &Context, // const volatile X&, and either there are no other parameters // or else all other parameters have default arguments (8.3.6). if ((getNumParams() < 1) || - (getNumParams() > 1 && getParamDecl(1)->getDefaultArg() == 0)) + (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg())) return false; const ParmVarDecl *Param = getParamDecl(0); @@ -363,7 +363,7 @@ bool CXXConstructorDecl::isConvertingConstructor() const { return (getNumParams() == 0 && getType()->getAsFunctionProtoType()->isVariadic()) || (getNumParams() == 1) || - (getNumParams() > 1 && getParamDecl(1)->getDefaultArg() != 0); + (getNumParams() > 1 && getParamDecl(1)->hasDefaultArg()); } CXXDestructorDecl * diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index f4bb895..21aefdd 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -42,6 +42,19 @@ void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) { // ObjCInterfaceDecl //===----------------------------------------------------------------------===// +/// getIvarDecl - This method looks up an ivar in this ContextDecl. +/// +ObjCIvarDecl * +ObjCContainerDecl::getIvarDecl(ASTContext &Context, IdentifierInfo *Id) const { + lookup_const_iterator Ivar, IvarEnd; + for (llvm::tie(Ivar, IvarEnd) = lookup(Context, Id); + Ivar != IvarEnd; ++Ivar) { + if (ObjCIvarDecl *ivar = dyn_cast<ObjCIvarDecl>(*Ivar)) + return ivar; + } + return 0; +} + // Get the local instance method declared in this interface. ObjCMethodDecl * ObjCContainerDecl::getInstanceMethod(ASTContext &Context, Selector Sel) const { @@ -139,12 +152,9 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable( ASTContext &Context, IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { ObjCInterfaceDecl* ClassDecl = this; while (ClassDecl != NULL) { - for (ivar_iterator I = ClassDecl->ivar_begin(), E = ClassDecl->ivar_end(); - I != E; ++I) { - if ((*I)->getIdentifier() == ID) { - clsDeclared = ClassDecl; - return *I; - } + if (ObjCIvarDecl *I = ClassDecl->getIvarDecl(Context, ID)) { + clsDeclared = ClassDecl; + return I; } // look into properties. for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(Context), diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index f29da8b..f231abf 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -508,8 +508,50 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { } void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { - // TODO: Write template parameters. - Out << "template <...> "; + Out << "template <"; + + TemplateParameterList *Params = D->getTemplateParameters(); + for (unsigned i = 0, e = Params->size(); i != e; ++i) { + if (i != 0) + Out << ", "; + + const Decl *Param = Params->getParam(i); + if (const TemplateTypeParmDecl *TTP = + dyn_cast<TemplateTypeParmDecl>(Param)) { + + QualType ParamType = + Context.getTypeDeclType(const_cast<TemplateTypeParmDecl*>(TTP)); + + if (TTP->wasDeclaredWithTypename()) + Out << "typename "; + else + Out << "class "; + + Out << ParamType.getAsString(Policy); + + if (TTP->hasDefaultArgument()) { + Out << " = "; + Out << TTP->getDefaultArgument().getAsString(Policy); + }; + } else if (const NonTypeTemplateParmDecl *NTTP = + dyn_cast<NonTypeTemplateParmDecl>(Param)) { + Out << NTTP->getType().getAsString(Policy); + + if (IdentifierInfo *Name = NTTP->getIdentifier()) { + Out << ' '; + Out << Name->getName(); + } + + if (NTTP->hasDefaultArgument()) { + Out << " = "; + NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy, + Indentation); + } + } + } + + Out << "> "; + Visit(D->getTemplatedDecl()); } diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index f38ee82..a534164 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -236,28 +236,42 @@ TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) { } //===----------------------------------------------------------------------===// +// TemplateArgumentListBuilder Implementation +//===----------------------------------------------------------------------===// +void TemplateArgumentListBuilder::push_back(const TemplateArgument& Arg) { + switch (Arg.getKind()) { + default: break; + case TemplateArgument::Type: + assert(Arg.getAsType()->isCanonical() && "Type must be canonical!"); + break; + } + + Args.push_back(Arg); +} + +//===----------------------------------------------------------------------===// // TemplateArgumentList Implementation //===----------------------------------------------------------------------===// TemplateArgumentList::TemplateArgumentList(ASTContext &Context, - TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, - bool CopyArgs) - : NumArguments(NumTemplateArgs) { + TemplateArgumentListBuilder &Builder, + bool CopyArgs, bool FlattenArgs) + : NumArguments(Builder.flatSize()) { if (!CopyArgs) { - Arguments.setPointer(TemplateArgs); + Arguments.setPointer(Builder.getFlatArgumentList()); Arguments.setInt(1); return; } - unsigned Size = sizeof(TemplateArgument) * NumTemplateArgs; + + unsigned Size = sizeof(TemplateArgument) * Builder.flatSize(); unsigned Align = llvm::AlignOf<TemplateArgument>::Alignment; void *Mem = Context.Allocate(Size, Align); Arguments.setPointer((TemplateArgument *)Mem); Arguments.setInt(0); TemplateArgument *Args = (TemplateArgument *)Mem; - for (unsigned I = 0; I != NumTemplateArgs; ++I) - new (Args + I) TemplateArgument(TemplateArgs[I]); + for (unsigned I = 0; I != NumArguments; ++I) + new (Args + I) TemplateArgument(Builder.getFlatArgumentList()[I]); } TemplateArgumentList::~TemplateArgumentList() { @@ -271,8 +285,7 @@ ClassTemplateSpecializationDecl:: ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, - TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs) + TemplateArgumentListBuilder &Builder) : CXXRecordDecl(DK, SpecializedTemplate->getTemplatedDecl()->getTagKind(), DC, L, @@ -280,7 +293,7 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, // class template specializations? SpecializedTemplate->getIdentifier()), SpecializedTemplate(SpecializedTemplate), - TemplateArgs(Context, TemplateArgs, NumTemplateArgs, /*CopyArgs=*/true), + TemplateArgs(Context, Builder, /*CopyArgs=*/true, /*FlattenArgs=*/true), SpecializationKind(TSK_Undeclared) { } @@ -288,16 +301,14 @@ ClassTemplateSpecializationDecl * ClassTemplateSpecializationDecl::Create(ASTContext &Context, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, - TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, + TemplateArgumentListBuilder &Builder, ClassTemplateSpecializationDecl *PrevDecl) { ClassTemplateSpecializationDecl *Result = new (Context)ClassTemplateSpecializationDecl(Context, ClassTemplateSpecialization, DC, L, SpecializedTemplate, - TemplateArgs, - NumTemplateArgs); + Builder); Context.getTypeDeclType(Result, PrevDecl); return Result; } @@ -310,14 +321,13 @@ ClassTemplatePartialSpecializationDecl:: Create(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, - TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + TemplateArgumentListBuilder &Builder, ClassTemplatePartialSpecializationDecl *PrevDecl) { ClassTemplatePartialSpecializationDecl *Result = new (Context)ClassTemplatePartialSpecializationDecl(Context, DC, L, Params, SpecializedTemplate, - TemplateArgs, - NumTemplateArgs); + Builder); Result->setSpecializationKind(TSK_ExplicitSpecialization); Context.getTypeDeclType(Result, PrevDecl); return Result; diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 4a15245..8fd66a2 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -305,10 +305,11 @@ void CXXConstructExpr::Destroy(ASTContext &C) { CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, CXXTemporary **temps, - unsigned numtemps) + unsigned numtemps, + bool destroytemps) : Expr(CXXExprWithTemporariesClass, subexpr->getType(), subexpr->isTypeDependent(), subexpr->isValueDependent()), - SubExpr(subexpr), Temps(0), NumTemps(numtemps) { + SubExpr(subexpr), Temps(0), NumTemps(numtemps), DestroyTemps(destroytemps) { if (NumTemps > 0) { Temps = new CXXTemporary*[NumTemps]; for (unsigned i = 0; i < NumTemps; ++i) @@ -319,8 +320,10 @@ CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C, Expr *SubExpr, CXXTemporary **Temps, - unsigned NumTemps) { - return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps); + unsigned NumTemps, + bool DestroyTemps) { + return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps, + DestroyTemps); } void CXXExprWithTemporaries::Destroy(ASTContext &C) { diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 50fdcfd..8e3c3ce 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -946,7 +946,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { const QualType ElementType = Type->getAsPointerType()->getPointeeType(); uint64_t D = LHSValue.getLValueOffset() - RHSValue.getLValueOffset(); - D /= Info.Ctx.getTypeSize(ElementType) / 8; + if (!ElementType->isVoidType() && !ElementType->isFunctionType()) + D /= Info.Ctx.getTypeSize(ElementType) / 8; return Success(D, E); } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index f573744..e304f54 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1049,6 +1049,10 @@ TemplateSpecializationType:: anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { for (unsigned Idx = 0; Idx < NumArgs; ++Idx) { switch (Args[Idx].getKind()) { + case TemplateArgument::Null: + assert(false && "Should not have a NULL template argument"); + break; + case TemplateArgument::Type: if (Args[Idx].getAsType()->isDependentType()) return true; @@ -1451,6 +1455,10 @@ TemplateSpecializationType::PrintTemplateArgumentList( // Print the argument into a string. std::string ArgString; switch (Args[Arg].getKind()) { + case TemplateArgument::Null: + assert(false && "Null template argument"); + break; + case TemplateArgument::Type: Args[Arg].getAsType().getAsStringInternal(ArgString, Policy); break; diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 30ff67f..532d16d 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -636,7 +636,11 @@ class VISIBILITY_HIDDEN RetainSummaryManager { /// ObjCAllocRetE - Default return effect for methods returning Objective-C /// objects. RetEffect ObjCAllocRetE; - + + /// ObjCInitRetE - Default return effect for init methods returning Objective-C + /// objects. + RetEffect ObjCInitRetE; + RetainSummary DefaultSummary; RetainSummary* StopSummary; @@ -776,6 +780,8 @@ public: GCEnabled(gcenabled), AF(BPAlloc), ScratchArgs(AF.GetEmptyMap()), ObjCAllocRetE(gcenabled ? RetEffect::MakeGCNotOwned() : RetEffect::MakeOwned(RetEffect::ObjC, true)), + ObjCInitRetE(gcenabled ? RetEffect::MakeGCNotOwned() + : RetEffect::MakeOwnedWhenTrackedReceiver()), DefaultSummary(AF.GetEmptyMap() /* per-argument effects (none) */, RetEffect::MakeNoRet() /* return effect */, MayEscape, /* default argument effect */ @@ -1156,8 +1162,7 @@ RetainSummaryManager::getInitMethodSummary(QualType RetTy) { // 'init' methods conceptually return a newly allocated object and claim // the receiver. if (isTrackedObjCObjectType(RetTy) || isTrackedCFObjectType(RetTy)) - return getPersistentSummary(RetEffect::MakeOwnedWhenTrackedReceiver(), - DecRefMsg); + return getPersistentSummary(ObjCInitRetE, DecRefMsg); return getDefaultSummary(); } @@ -1168,12 +1173,19 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, if (!FD) return; + QualType RetTy = FD->getResultType(); + // Determine if there is a special return effect for this method. - if (isTrackedObjCObjectType(FD->getResultType())) { + if (isTrackedObjCObjectType(RetTy)) { if (FD->getAttr<NSReturnsRetainedAttr>()) { Summ.setRetEffect(ObjCAllocRetE); } - else if (FD->getAttr<CFReturnsRetainedAttr>()) { + else if (FD->getAttr<CFReturnsRetainedAttr>()) { + Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); + } + } + else if (RetTy->getAsPointerType()) { + if (FD->getAttr<CFReturnsRetainedAttr>()) { Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); } } @@ -1367,8 +1379,7 @@ void RetainSummaryManager::InitializeMethodSummaries() { // Create the "init" selector. It just acts as a pass-through for the // receiver. addNSObjectMethSummary(GetNullarySelector("init", Ctx), - getPersistentSummary(RetEffect::MakeOwnedWhenTrackedReceiver(), - DecRefMsg)); + getPersistentSummary(ObjCInitRetE, DecRefMsg)); // The next methods are allocators. RetainSummary *AllocSumm = getPersistentSummary(ObjCAllocRetE); diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 1e8ca2b..a513cb1 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -22,7 +22,6 @@ 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; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 4b94bcf..120d525 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -182,6 +182,11 @@ static void getDarwinDefines(std::vector<char> &Defs, const LangOptions &Opts) { Define(Defs, "__strong", ""); else Define(Defs, "__strong", "__attribute__((objc_gc(strong)))"); + + if (Opts.Static) + Define(Defs, "__STATIC__"); + else + Define(Defs, "__DYNAMIC__"); } static void getDarwinOSXDefines(std::vector<char> &Defs, const char *Triple) { @@ -252,9 +257,8 @@ class PPCTargetInfo : public TargetInfo { static const TargetInfo::GCCRegAlias GCCRegAliases[]; public: - PPCTargetInfo(const std::string& triple) : TargetInfo(triple) { - CharIsSigned = false; - } + PPCTargetInfo(const std::string& triple) : TargetInfo(triple) {} + virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { Records = BuiltinInfo; @@ -294,6 +298,10 @@ public: return true; } } + virtual void getDefaultLangOptions(LangOptions &Opts) { + TargetInfo::getDefaultLangOptions(Opts); + Opts.CharIsSigned = false; + } virtual const char *getClobbers() const { return ""; } @@ -444,6 +452,7 @@ public: /// various language options. These may be overridden by command line /// options. virtual void getDefaultLangOptions(LangOptions &Opts) { + PPC32TargetInfo::getDefaultLangOptions(Opts); GetDarwinLanguageOptions(Opts, getTargetTriple()); } }; @@ -464,6 +473,7 @@ public: /// various language options. These may be overridden by command line /// options. virtual void getDefaultLangOptions(LangOptions &Opts) { + PPC64TargetInfo::getDefaultLangOptions(Opts); GetDarwinLanguageOptions(Opts, getTargetTriple()); } }; @@ -840,6 +850,7 @@ public: /// various language options. These may be overridden by command line /// options. virtual void getDefaultLangOptions(LangOptions &Opts) { + X86_32TargetInfo::getDefaultLangOptions(Opts); GetDarwinLanguageOptions(Opts, getTargetTriple()); } }; diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h index 3de4612..44af0c4 100644 --- a/lib/CodeGen/ABIInfo.h +++ b/lib/CodeGen/ABIInfo.h @@ -10,8 +10,13 @@ #ifndef CLANG_CODEGEN_ABIINFO_H #define CLANG_CODEGEN_ABIINFO_H +#include "clang/AST/Type.h" + +#include <cassert> + namespace llvm { class Type; + class Value; } namespace clang { @@ -38,32 +43,32 @@ namespace clang { Direct, /// Pass the argument directly using the normal /// converted LLVM type. Complex and structure types /// are passed using first class aggregates. - + Indirect, /// Pass the argument indirectly via a hidden pointer /// with the specified alignment (0 indicates default /// alignment). - + Ignore, /// Ignore the argument (treat as void). Useful for /// void and empty structs. - + Coerce, /// Only valid for aggregate return types, the argument /// should be accessed by coercion to a provided type. - + Expand, /// Only valid for aggregate argument types. The /// structure should be expanded into consecutive /// arguments for its constituent fields. Currently /// expand is only allowed on structures whose fields /// are all scalar types or are themselves expandable /// types. - + KindFirst=Direct, KindLast=Expand }; - + private: Kind TheKind; const llvm::Type *TypeData; unsigned UIntData; - + ABIArgInfo(Kind K, const llvm::Type *TD=0, unsigned UI=0) : TheKind(K), TypeData(TD), @@ -71,13 +76,13 @@ namespace clang { public: ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {} - static ABIArgInfo getDirect() { - return ABIArgInfo(Direct); + static ABIArgInfo getDirect() { + return ABIArgInfo(Direct); } static ABIArgInfo getIgnore() { return ABIArgInfo(Ignore); } - static ABIArgInfo getCoerce(const llvm::Type *T) { + static ABIArgInfo getCoerce(const llvm::Type *T) { return ABIArgInfo(Coerce, T); } static ABIArgInfo getIndirect(unsigned Alignment) { @@ -86,20 +91,20 @@ namespace clang { static ABIArgInfo getExpand() { return ABIArgInfo(Expand); } - + Kind getKind() const { return TheKind; } bool isDirect() const { return TheKind == Direct; } bool isIgnore() const { return TheKind == Ignore; } bool isCoerce() const { return TheKind == Coerce; } bool isIndirect() const { return TheKind == Indirect; } bool isExpand() const { return TheKind == Expand; } - + // Coerce accessors const llvm::Type *getCoerceToType() const { assert(TheKind == Coerce && "Invalid kind!"); return TypeData; } - + // ByVal accessors unsigned getIndirectAlign() const { assert(TheKind == Indirect && "Invalid kind!"); @@ -120,7 +125,7 @@ namespace clang { /// EmitVAArg - Emit the target dependent code to load a value of /// \arg Ty from the va_list pointed to by \arg VAListAddr. - + // FIXME: This is a gaping layering violation if we wanted to drop // the ABI information any lower than CodeGen. Of course, for // VAArg handling it has to be at this level; there is no way to diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index ead689c..d5f803b 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -724,6 +724,8 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); + // FIXME: We'd like to put these into a mergable by content, with + // internal linkage. std::string Name = std::string("__copy_helper_block_"); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); @@ -803,6 +805,8 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); + // FIXME: We'd like to put these into a mergable by content, with + // internal linkage. std::string Name = std::string("__destroy_helper_block_"); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); @@ -889,6 +893,8 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); + // FIXME: We'd like to put these into a mergable by content, with + // internal linkage. llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, Name, @@ -950,6 +956,8 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); + // FIXME: We'd like to put these into a mergable by content, with + // internal linkage. llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, Name, @@ -980,13 +988,36 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, } llvm::Constant *BlockFunction::BuildbyrefCopyHelper(const llvm::Type *T, - int flag) { - return CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, flag); + int flag, unsigned Align) { + // All alignments below that of pointer alignment collpase down to just + // pointer alignment, as we always have at least that much alignment to begin + // with. + Align /= unsigned(CGF.Target.getPointerAlign(0)/8); + // As an optimization, we only generate a single function of each kind we + // might need. We need a different one for each alignment and for each + // setting of flags. We mix Align and flag to get the kind. + uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag; + llvm::Constant *& Entry = CGM.AssignCache[kind]; + if (Entry) + return Entry; + return Entry=CodeGenFunction(CGM).GeneratebyrefCopyHelperFunction(T, flag); } llvm::Constant *BlockFunction::BuildbyrefDestroyHelper(const llvm::Type *T, - int flag) { - return CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, flag); + int flag, + unsigned Align) { + // All alignments below that of pointer alignment collpase down to just + // pointer alignment, as we always have at least that much alignment to begin + // with. + Align /= unsigned(CGF.Target.getPointerAlign(0)/8); + // As an optimization, we only generate a single function of each kind we + // might need. We need a different one for each alignment and for each + // setting of flags. We mix Align and flag to get the kind. + uint64_t kind = (uint64_t)Align*BLOCK_BYREF_CURRENT_MAX + flag; + llvm::Constant *& Entry = CGM.DestroyCache[kind]; + if (Entry) + return Entry; + return Entry=CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, flag); } llvm::Value *BlockFunction::getBlockObjectDispose() { diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 56d3a2d..5d46ac7 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -98,6 +98,9 @@ public: llvm::Value *BlockObjectDispose; const llvm::Type *PtrToInt8Ty; + std::map<uint64_t, llvm::Constant *> AssignCache; + std::map<uint64_t, llvm::Constant *> DestroyCache; + BlockModule(ASTContext &C, llvm::Module &M, const llvm::TargetData &TD, CodeGenTypes &T, CodeGenModule &CodeGen) : Context(C), TheModule(M), TheTargetData(TD), Types(T), @@ -131,8 +134,9 @@ public: variable */ BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy helpers */ - BLOCK_BYREF_CALLER = 128 /* called from __block (byref) copy/dispose + BLOCK_BYREF_CALLER = 128, /* called from __block (byref) copy/dispose support routines */ + BLOCK_BYREF_CURRENT_MAX = 256 }; /// BlockInfo - Information to generate a block literal. @@ -199,8 +203,10 @@ public: llvm::Constant *GeneratebyrefCopyHelperFunction(const llvm::Type *, int flag); llvm::Constant *GeneratebyrefDestroyHelperFunction(const llvm::Type *T, int); - llvm::Constant *BuildbyrefCopyHelper(const llvm::Type *T, int flag); - llvm::Constant *BuildbyrefDestroyHelper(const llvm::Type *T, int flag); + llvm::Constant *BuildbyrefCopyHelper(const llvm::Type *T, int flag, + unsigned Align); + llvm::Constant *BuildbyrefDestroyHelper(const llvm::Type *T, int flag, + unsigned Align); llvm::Value *getBlockObjectAssign(); llvm::Value *getBlockObjectDispose(); diff --git a/lib/CodeGen/CGCXXTemp.cpp b/lib/CodeGen/CGCXXTemp.cpp index d53a56f..141726a 100644 --- a/lib/CodeGen/CGCXXTemp.cpp +++ b/lib/CodeGen/CGCXXTemp.cpp @@ -18,8 +18,29 @@ using namespace CodeGen; void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr) { llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor"); - - LiveTemporaries.push_back(CXXLiveTemporaryInfo(Temporary, Ptr, DtorBlock, 0)); + + llvm::Value *CondPtr = 0; + + // Check if temporaries need to be conditional. If so, we'll create a + // condition boolean, initialize it to 0 and + if (!ConditionalTempDestructionStack.empty()) { + CondPtr = CreateTempAlloca(llvm::Type::Int1Ty, "cond"); + + // Initialize it to false. This initialization takes place right after + // the alloca insert point. + llvm::StoreInst *SI = + new llvm::StoreInst(llvm::ConstantInt::getFalse(), CondPtr); + llvm::BasicBlock *Block = AllocaInsertPt->getParent(); + Block->getInstList().insertAfter((llvm::Instruction *)AllocaInsertPt, SI); + + // Now set it to true. + Builder.CreateStore(llvm::ConstantInt::getTrue(), CondPtr); + } + + LiveTemporaries.push_back(CXXLiveTemporaryInfo(Temporary, Ptr, DtorBlock, + CondPtr)); + + PushCleanupBlock(DtorBlock); } void CodeGenFunction::PopCXXTemporary() { @@ -35,9 +56,28 @@ void CodeGenFunction::PopCXXTemporary() { EmitBlock(Info.DtorBlock); + llvm::BasicBlock *CondEnd = 0; + + // If this is a conditional temporary, we need to check the condition + // boolean and only call the destructor if it's true. + if (Info.CondPtr) { + llvm::BasicBlock *CondBlock = createBasicBlock("cond.dtor.call"); + CondEnd = createBasicBlock("cond.dtor.end"); + + llvm::Value *Cond = Builder.CreateLoad(Info.CondPtr); + Builder.CreateCondBr(Cond, CondBlock, CondEnd); + EmitBlock(CondBlock); + } + EmitCXXDestructorCall(Info.Temporary->getDestructor(), Dtor_Complete, Info.ThisPtr); + if (CondEnd) { + // Reset the condition. to false. + Builder.CreateStore(llvm::ConstantInt::getFalse(), Info.CondPtr); + EmitBlock(CondEnd); + } + LiveTemporaries.pop_back(); } @@ -47,21 +87,38 @@ CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, bool isAggLocVolatile) { // Keep track of the current cleanup stack depth. size_t CleanupStackDepth = CleanupEntries.size(); + (void) CleanupStackDepth; unsigned OldNumLiveTemporaries = LiveTemporaries.size(); RValue RV = EmitAnyExpr(E->getSubExpr(), AggLoc, isAggLocVolatile); - // Go through the temporaries backwards. - for (unsigned i = E->getNumTemporaries(); i != 0; --i) { - assert(LiveTemporaries.back().Temporary == E->getTemporary(i - 1)); - LiveTemporaries.pop_back(); - } + // Pop temporaries. + while (LiveTemporaries.size() > OldNumLiveTemporaries) + PopCXXTemporary(); + + assert(CleanupEntries.size() == CleanupStackDepth && + "Cleanup size mismatch!"); + + return RV; +} + +void +CodeGenFunction::PushConditionalTempDestruction() { + // Store the current number of live temporaries. + ConditionalTempDestructionStack.push_back(LiveTemporaries.size()); +} - assert(OldNumLiveTemporaries == LiveTemporaries.size() && - "Live temporary stack mismatch!"); +void CodeGenFunction::PopConditionalTempDestruction() { + size_t NumLiveTemporaries = ConditionalTempDestructionStack.back(); + ConditionalTempDestructionStack.pop_back(); - EmitCleanupBlocks(CleanupStackDepth); + // Pop temporaries. + while (LiveTemporaries.size() > NumLiveTemporaries) { + assert(LiveTemporaries.back().CondPtr && + "Conditional temporary must have a cond ptr!"); - return RV; + PopCXXTemporary(); + } } + diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index ea0b887..b46e860 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -16,15 +16,12 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/Basic/TargetInfo.h" -#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" -#include "clang/AST/RecordLayout.h" -#include "llvm/ADT/StringExtras.h" +#include "clang/Frontend/CompileOptions.h" #include "llvm/Attributes.h" #include "llvm/Support/CallSite.h" -#include "llvm/Support/MathExtras.h" #include "llvm/Target/TargetData.h" #include "ABIInfo.h" @@ -126,1370 +123,6 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, return *FI; } -/***/ - -ABIInfo::~ABIInfo() {} - -void ABIArgInfo::dump() const { - fprintf(stderr, "(ABIArgInfo Kind="); - switch (TheKind) { - case Direct: - fprintf(stderr, "Direct"); - break; - case Ignore: - fprintf(stderr, "Ignore"); - break; - case Coerce: - fprintf(stderr, "Coerce Type="); - getCoerceToType()->print(llvm::errs()); - break; - case Indirect: - fprintf(stderr, "Indirect Align=%d", getIndirectAlign()); - break; - case Expand: - fprintf(stderr, "Expand"); - break; - } - fprintf(stderr, ")\n"); -} - -/***/ - -static bool isEmptyRecord(ASTContext &Context, QualType T); - -/// isEmptyField - Return true iff a the field is "empty", that is it -/// is an unnamed bit-field or an (array of) empty record(s). -static bool isEmptyField(ASTContext &Context, const FieldDecl *FD) { - if (FD->isUnnamedBitfield()) - return true; - - QualType FT = FD->getType(); - // Constant arrays of empty records count as empty, strip them off. - while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) - FT = AT->getElementType(); - - return isEmptyRecord(Context, FT); -} - -/// isEmptyRecord - Return true iff a structure contains only empty -/// fields. Note that a structure with a flexible array member is not -/// considered empty. -static bool isEmptyRecord(ASTContext &Context, QualType T) { - const RecordType *RT = T->getAsRecordType(); - if (!RT) - return 0; - const RecordDecl *RD = RT->getDecl(); - if (RD->hasFlexibleArrayMember()) - return false; - for (RecordDecl::field_iterator i = RD->field_begin(Context), - e = RD->field_end(Context); i != e; ++i) - if (!isEmptyField(Context, *i)) - return false; - return true; -} - -/// isSingleElementStruct - Determine if a structure is a "single -/// element struct", i.e. it has exactly one non-empty field or -/// exactly one field which is itself a single element -/// struct. Structures with flexible array members are never -/// considered single element structs. -/// -/// \return The field declaration for the single non-empty field, if -/// it exists. -static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { - const RecordType *RT = T->getAsStructureType(); - if (!RT) - return 0; - - const RecordDecl *RD = RT->getDecl(); - if (RD->hasFlexibleArrayMember()) - return 0; - - const Type *Found = 0; - for (RecordDecl::field_iterator i = RD->field_begin(Context), - e = RD->field_end(Context); i != e; ++i) { - const FieldDecl *FD = *i; - QualType FT = FD->getType(); - - // Ignore empty fields. - if (isEmptyField(Context, FD)) - continue; - - // If we already found an element then this isn't a single-element - // struct. - if (Found) - return 0; - - // Treat single element arrays as the element. - while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { - if (AT->getSize().getZExtValue() != 1) - break; - FT = AT->getElementType(); - } - - if (!CodeGenFunction::hasAggregateLLVMType(FT)) { - Found = FT.getTypePtr(); - } else { - Found = isSingleElementStruct(FT, Context); - if (!Found) - return 0; - } - } - - return Found; -} - -static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) { - if (!Ty->getAsBuiltinType() && !Ty->isPointerType()) - return false; - - uint64_t Size = Context.getTypeSize(Ty); - return Size == 32 || Size == 64; -} - -static bool areAllFields32Or64BitBasicType(const RecordDecl *RD, - ASTContext &Context) { - for (RecordDecl::field_iterator i = RD->field_begin(Context), - e = RD->field_end(Context); i != e; ++i) { - const FieldDecl *FD = *i; - - if (!is32Or64BitBasicType(FD->getType(), Context)) - return false; - - // FIXME: Reject bit-fields wholesale; there are two problems, we don't know - // how to expand them yet, and the predicate for telling if a bitfield still - // counts as "basic" is more complicated than what we were doing previously. - if (FD->isBitField()) - return false; - } - - return true; -} - -namespace { -/// DefaultABIInfo - The default implementation for ABI specific -/// details. This implementation provides information which results in -/// self-consistent and sensible LLVM IR generation, but does not -/// conform to any particular ABI. -class DefaultABIInfo : public ABIInfo { - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type, Context); - } - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; - -/// X86_32ABIInfo - The X86-32 ABI information. -class X86_32ABIInfo : public ABIInfo { - ASTContext &Context; - bool IsDarwin; - - static bool isRegisterSize(unsigned Size) { - return (Size == 8 || Size == 16 || Size == 32 || Size == 64); - } - - static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context); - -public: - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type, Context); - } - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; - - X86_32ABIInfo(ASTContext &Context, bool d) - : ABIInfo(), Context(Context), IsDarwin(d) {} -}; -} - - -/// shouldReturnTypeInRegister - Determine if the given type should be -/// passed in a register (for the Darwin ABI). -bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, - ASTContext &Context) { - uint64_t Size = Context.getTypeSize(Ty); - - // Type must be register sized. - if (!isRegisterSize(Size)) - return false; - - if (Ty->isVectorType()) { - // 64- and 128- bit vectors inside structures are not returned in - // registers. - if (Size == 64 || Size == 128) - return false; - - return true; - } - - // If this is a builtin, pointer, or complex type, it is ok. - if (Ty->getAsBuiltinType() || Ty->isPointerType() || Ty->isAnyComplexType()) - return true; - - // Arrays are treated like records. - if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) - return shouldReturnTypeInRegister(AT->getElementType(), Context); - - // Otherwise, it must be a record type. - const RecordType *RT = Ty->getAsRecordType(); - if (!RT) return false; - - // Structure types are passed in register if all fields would be - // passed in a register. - for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(Context), - e = RT->getDecl()->field_end(Context); i != e; ++i) { - const FieldDecl *FD = *i; - - // Empty fields are ignored. - if (isEmptyField(Context, FD)) - continue; - - // Check fields recursively. - if (!shouldReturnTypeInRegister(FD->getType(), Context)) - return false; - } - - return true; -} - -ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else if (const VectorType *VT = RetTy->getAsVectorType()) { - // On Darwin, some vectors are returned in registers. - if (IsDarwin) { - uint64_t Size = Context.getTypeSize(RetTy); - - // 128-bit vectors are a special case; they are returned in - // registers and we need to make sure to pick a type the LLVM - // backend will like. - if (Size == 128) - return ABIArgInfo::getCoerce(llvm::VectorType::get(llvm::Type::Int64Ty, - 2)); - - // Always return in register if it fits in a general purpose - // register, or if it is 64 bits and has a single element. - if ((Size == 8 || Size == 16 || Size == 32) || - (Size == 64 && VT->getNumElements() == 1)) - return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size)); - - return ABIArgInfo::getIndirect(0); - } - - return ABIArgInfo::getDirect(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - // Structures with flexible arrays are always indirect. - if (const RecordType *RT = RetTy->getAsStructureType()) - if (RT->getDecl()->hasFlexibleArrayMember()) - return ABIArgInfo::getIndirect(0); - - // Outside of Darwin, structs and unions are always indirect. - if (!IsDarwin && !RetTy->isAnyComplexType()) - return ABIArgInfo::getIndirect(0); - - // Classify "single element" structs as their element type. - if (const Type *SeltTy = isSingleElementStruct(RetTy, Context)) { - if (const BuiltinType *BT = SeltTy->getAsBuiltinType()) { - if (BT->isIntegerType()) { - // We need to use the size of the structure, padding - // bit-fields can adjust that to be larger than the single - // element type. - uint64_t Size = Context.getTypeSize(RetTy); - return ABIArgInfo::getCoerce(llvm::IntegerType::get((unsigned) Size)); - } else if (BT->getKind() == BuiltinType::Float) { - assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && - "Unexpect single element structure size!"); - return ABIArgInfo::getCoerce(llvm::Type::FloatTy); - } else if (BT->getKind() == BuiltinType::Double) { - assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && - "Unexpect single element structure size!"); - return ABIArgInfo::getCoerce(llvm::Type::DoubleTy); - } - } else if (SeltTy->isPointerType()) { - // FIXME: It would be really nice if this could come out as the proper - // pointer type. - llvm::Type *PtrTy = - llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - return ABIArgInfo::getCoerce(PtrTy); - } else if (SeltTy->isVectorType()) { - // 64- and 128-bit vectors are never returned in a - // register when inside a structure. - uint64_t Size = Context.getTypeSize(RetTy); - if (Size == 64 || Size == 128) - return ABIArgInfo::getIndirect(0); - - return classifyReturnType(QualType(SeltTy, 0), Context); - } - } - - // Small structures which are register sized are generally returned - // in a register. - if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context)) { - uint64_t Size = Context.getTypeSize(RetTy); - return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size)); - } - - return ABIArgInfo::getIndirect(0); - } else { - return ABIArgInfo::getDirect(); - } -} - -ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context) const { - // FIXME: Set alignment on indirect arguments. - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { - // Structures with flexible arrays are always indirect. - if (const RecordType *RT = Ty->getAsStructureType()) - if (RT->getDecl()->hasFlexibleArrayMember()) - return ABIArgInfo::getIndirect(0); - - // Ignore empty structs. - uint64_t Size = Context.getTypeSize(Ty); - if (Ty->isStructureType() && Size == 0) - return ABIArgInfo::getIgnore(); - - // Expand structs with size <= 128-bits which consist only of - // basic types (int, long long, float, double, xxx*). This is - // non-recursive and does not ignore empty fields. - if (const RecordType *RT = Ty->getAsStructureType()) { - if (Context.getTypeSize(Ty) <= 4*32 && - areAllFields32Or64BitBasicType(RT->getDecl(), Context)) - return ABIArgInfo::getExpand(); - } - - return ABIArgInfo::getIndirect(0); - } else { - return ABIArgInfo::getDirect(); - } -} - -llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); - - CGBuilderTy &Builder = CGF.Builder; - llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, - "ap"); - llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); - llvm::Type *PTy = - llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); - llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); - - uint64_t Offset = - llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4); - llvm::Value *NextAddr = - Builder.CreateGEP(Addr, - llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset), - "ap.next"); - Builder.CreateStore(NextAddr, VAListAddrAsBPP); - - return AddrTyped; -} - -namespace { -/// X86_64ABIInfo - The X86_64 ABI information. -class X86_64ABIInfo : public ABIInfo { - enum Class { - Integer = 0, - SSE, - SSEUp, - X87, - X87Up, - ComplexX87, - NoClass, - Memory - }; - - /// merge - Implement the X86_64 ABI merging algorithm. - /// - /// Merge an accumulating classification \arg Accum with a field - /// classification \arg Field. - /// - /// \param Accum - The accumulating classification. This should - /// always be either NoClass or the result of a previous merge - /// call. In addition, this should never be Memory (the caller - /// should just return Memory for the aggregate). - Class merge(Class Accum, Class Field) const; - - /// classify - Determine the x86_64 register classes in which the - /// given type T should be passed. - /// - /// \param Lo - The classification for the parts of the type - /// residing in the low word of the containing object. - /// - /// \param Hi - The classification for the parts of the type - /// residing in the high word of the containing object. - /// - /// \param OffsetBase - The bit offset of this type in the - /// containing object. Some parameters are classified different - /// depending on whether they straddle an eightbyte boundary. - /// - /// If a word is unused its result will be NoClass; if a type should - /// be passed in Memory then at least the classification of \arg Lo - /// will be Memory. - /// - /// The \arg Lo class will be NoClass iff the argument is ignored. - /// - /// If the \arg Lo class is ComplexX87, then the \arg Hi class will - /// also be ComplexX87. - void classify(QualType T, ASTContext &Context, uint64_t OffsetBase, - Class &Lo, Class &Hi) const; - - /// getCoerceResult - Given a source type \arg Ty and an LLVM type - /// to coerce to, chose the best way to pass Ty in the same place - /// that \arg CoerceTo would be passed, but while keeping the - /// emitted code as simple as possible. - /// - /// FIXME: Note, this should be cleaned up to just take an enumeration of all - /// the ways we might want to pass things, instead of constructing an LLVM - /// type. This makes this code more explicit, and it makes it clearer that we - /// are also doing this for correctness in the case of passing scalar types. - ABIArgInfo getCoerceResult(QualType Ty, - const llvm::Type *CoerceTo, - ASTContext &Context) const; - - /// getIndirectResult - Give a source type \arg Ty, return a suitable result - /// such that the argument will be passed in memory. - ABIArgInfo getIndirectResult(QualType Ty, - ASTContext &Context) const; - - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context) const; - - ABIArgInfo classifyArgumentType(QualType Ty, - ASTContext &Context, - unsigned &neededInt, - unsigned &neededSSE) const; - -public: - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const; - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; -} - -X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, - Class Field) const { - // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is - // classified recursively so that always two fields are - // considered. The resulting class is calculated according to - // the classes of the fields in the eightbyte: - // - // (a) If both classes are equal, this is the resulting class. - // - // (b) If one of the classes is NO_CLASS, the resulting class is - // the other class. - // - // (c) If one of the classes is MEMORY, the result is the MEMORY - // class. - // - // (d) If one of the classes is INTEGER, the result is the - // INTEGER. - // - // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class, - // MEMORY is used as class. - // - // (f) Otherwise class SSE is used. - - // Accum should never be memory (we should have returned) or - // ComplexX87 (because this cannot be passed in a structure). - assert((Accum != Memory && Accum != ComplexX87) && - "Invalid accumulated classification during merge."); - if (Accum == Field || Field == NoClass) - return Accum; - else if (Field == Memory) - return Memory; - else if (Accum == NoClass) - return Field; - else if (Accum == Integer || Field == Integer) - return Integer; - else if (Field == X87 || Field == X87Up || Field == ComplexX87 || - Accum == X87 || Accum == X87Up) - return Memory; - else - return SSE; -} - -void X86_64ABIInfo::classify(QualType Ty, - ASTContext &Context, - uint64_t OffsetBase, - Class &Lo, Class &Hi) const { - // FIXME: This code can be simplified by introducing a simple value class for - // Class pairs with appropriate constructor methods for the various - // situations. - - // FIXME: Some of the split computations are wrong; unaligned vectors - // shouldn't be passed in registers for example, so there is no chance they - // can straddle an eightbyte. Verify & simplify. - - Lo = Hi = NoClass; - - Class &Current = OffsetBase < 64 ? Lo : Hi; - Current = Memory; - - if (const BuiltinType *BT = Ty->getAsBuiltinType()) { - BuiltinType::Kind k = BT->getKind(); - - if (k == BuiltinType::Void) { - Current = NoClass; - } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { - Lo = Integer; - Hi = Integer; - } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) { - Current = Integer; - } else if (k == BuiltinType::Float || k == BuiltinType::Double) { - Current = SSE; - } else if (k == BuiltinType::LongDouble) { - Lo = X87; - Hi = X87Up; - } - // FIXME: _Decimal32 and _Decimal64 are SSE. - // FIXME: _float128 and _Decimal128 are (SSE, SSEUp). - } else if (const EnumType *ET = Ty->getAsEnumType()) { - // Classify the underlying integer type. - classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi); - } else if (Ty->hasPointerRepresentation()) { - Current = Integer; - } else if (const VectorType *VT = Ty->getAsVectorType()) { - uint64_t Size = Context.getTypeSize(VT); - if (Size == 32) { - // gcc passes all <4 x char>, <2 x short>, <1 x int>, <1 x - // float> as integer. - Current = Integer; - - // If this type crosses an eightbyte boundary, it should be - // split. - uint64_t EB_Real = (OffsetBase) / 64; - uint64_t EB_Imag = (OffsetBase + Size - 1) / 64; - if (EB_Real != EB_Imag) - Hi = Lo; - } else if (Size == 64) { - // gcc passes <1 x double> in memory. :( - if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double)) - return; - - // gcc passes <1 x long long> as INTEGER. - if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong)) - Current = Integer; - else - Current = SSE; - - // If this type crosses an eightbyte boundary, it should be - // split. - if (OffsetBase && OffsetBase != 64) - Hi = Lo; - } else if (Size == 128) { - Lo = SSE; - Hi = SSEUp; - } - } else if (const ComplexType *CT = Ty->getAsComplexType()) { - QualType ET = Context.getCanonicalType(CT->getElementType()); - - uint64_t Size = Context.getTypeSize(Ty); - if (ET->isIntegralType()) { - if (Size <= 64) - Current = Integer; - else if (Size <= 128) - Lo = Hi = Integer; - } else if (ET == Context.FloatTy) - Current = SSE; - else if (ET == Context.DoubleTy) - Lo = Hi = SSE; - else if (ET == Context.LongDoubleTy) - Current = ComplexX87; - - // If this complex type crosses an eightbyte boundary then it - // should be split. - uint64_t EB_Real = (OffsetBase) / 64; - uint64_t EB_Imag = (OffsetBase + Context.getTypeSize(ET)) / 64; - if (Hi == NoClass && EB_Real != EB_Imag) - Hi = Lo; - } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { - // Arrays are treated like structures. - - uint64_t Size = Context.getTypeSize(Ty); - - // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger - // than two eightbytes, ..., it has class MEMORY. - if (Size > 128) - return; - - // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned - // fields, it has class MEMORY. - // - // Only need to check alignment of array base. - if (OffsetBase % Context.getTypeAlign(AT->getElementType())) - return; - - // Otherwise implement simplified merge. We could be smarter about - // this, but it isn't worth it and would be harder to verify. - Current = NoClass; - uint64_t EltSize = Context.getTypeSize(AT->getElementType()); - uint64_t ArraySize = AT->getSize().getZExtValue(); - for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) { - Class FieldLo, FieldHi; - classify(AT->getElementType(), Context, Offset, FieldLo, FieldHi); - Lo = merge(Lo, FieldLo); - Hi = merge(Hi, FieldHi); - if (Lo == Memory || Hi == Memory) - break; - } - - // Do post merger cleanup (see below). Only case we worry about is Memory. - if (Hi == Memory) - Lo = Memory; - assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification."); - } else if (const RecordType *RT = Ty->getAsRecordType()) { - uint64_t Size = Context.getTypeSize(Ty); - - // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger - // than two eightbytes, ..., it has class MEMORY. - if (Size > 128) - return; - - const RecordDecl *RD = RT->getDecl(); - - // Assume variable sized types are passed in memory. - if (RD->hasFlexibleArrayMember()) - return; - - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - // Reset Lo class, this will be recomputed. - Current = NoClass; - unsigned idx = 0; - for (RecordDecl::field_iterator i = RD->field_begin(Context), - e = RD->field_end(Context); i != e; ++i, ++idx) { - uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); - bool BitField = i->isBitField(); - - // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned - // fields, it has class MEMORY. - // - // Note, skip this test for bit-fields, see below. - if (!BitField && Offset % Context.getTypeAlign(i->getType())) { - Lo = Memory; - return; - } - - // Classify this field. - // - // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate - // exceeds a single eightbyte, each is classified - // separately. Each eightbyte gets initialized to class - // NO_CLASS. - Class FieldLo, FieldHi; - - // Bit-fields require special handling, they do not force the - // structure to be passed in memory even if unaligned, and - // therefore they can straddle an eightbyte. - if (BitField) { - // Ignore padding bit-fields. - if (i->isUnnamedBitfield()) - continue; - - uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); - uint64_t Size = i->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); - - uint64_t EB_Lo = Offset / 64; - uint64_t EB_Hi = (Offset + Size - 1) / 64; - FieldLo = FieldHi = NoClass; - if (EB_Lo) { - assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes."); - FieldLo = NoClass; - FieldHi = Integer; - } else { - FieldLo = Integer; - FieldHi = EB_Hi ? Integer : NoClass; - } - } else - classify(i->getType(), Context, Offset, FieldLo, FieldHi); - Lo = merge(Lo, FieldLo); - Hi = merge(Hi, FieldHi); - if (Lo == Memory || Hi == Memory) - break; - } - - // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done: - // - // (a) If one of the classes is MEMORY, the whole argument is - // passed in memory. - // - // (b) If SSEUP is not preceeded by SSE, it is converted to SSE. - - // The first of these conditions is guaranteed by how we implement - // the merge (just bail). - // - // The second condition occurs in the case of unions; for example - // union { _Complex double; unsigned; }. - if (Hi == Memory) - Lo = Memory; - if (Hi == SSEUp && Lo != SSE) - Hi = SSE; - } -} - -ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty, - const llvm::Type *CoerceTo, - ASTContext &Context) const { - if (CoerceTo == llvm::Type::Int64Ty) { - // Integer and pointer types will end up in a general purpose - // register. - if (Ty->isIntegralType() || Ty->isPointerType()) - return ABIArgInfo::getDirect(); - - } else if (CoerceTo == llvm::Type::DoubleTy) { - // FIXME: It would probably be better to make CGFunctionInfo only map using - // canonical types than to canonize here. - QualType CTy = Context.getCanonicalType(Ty); - - // Float and double end up in a single SSE reg. - if (CTy == Context.FloatTy || CTy == Context.DoubleTy) - return ABIArgInfo::getDirect(); - - } - - return ABIArgInfo::getCoerce(CoerceTo); -} - -ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, - ASTContext &Context) const { - // If this is a scalar LLVM value then assume LLVM will pass it in the right - // place naturally. - if (!CodeGenFunction::hasAggregateLLVMType(Ty)) - return ABIArgInfo::getDirect(); - - // FIXME: Set alignment correctly. - return ABIArgInfo::getIndirect(0); -} - -ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context) const { - // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the - // classification algorithm. - X86_64ABIInfo::Class Lo, Hi; - classify(RetTy, Context, 0, Lo, Hi); - - // Check some invariants. - assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); - assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); - assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); - - const llvm::Type *ResType = 0; - switch (Lo) { - case NoClass: - return ABIArgInfo::getIgnore(); - - case SSEUp: - case X87Up: - assert(0 && "Invalid classification for lo word."); - - // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via - // hidden argument. - case Memory: - return getIndirectResult(RetTy, Context); - - // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next - // available register of the sequence %rax, %rdx is used. - case Integer: - ResType = llvm::Type::Int64Ty; break; - - // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next - // available SSE register of the sequence %xmm0, %xmm1 is used. - case SSE: - ResType = llvm::Type::DoubleTy; break; - - // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is - // returned on the X87 stack in %st0 as 80-bit x87 number. - case X87: - ResType = llvm::Type::X86_FP80Ty; break; - - // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real - // part of the value is returned in %st0 and the imaginary part in - // %st1. - case ComplexX87: - assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification."); - ResType = llvm::StructType::get(llvm::Type::X86_FP80Ty, - llvm::Type::X86_FP80Ty, - NULL); - break; - } - - switch (Hi) { - // Memory was handled previously and X87 should - // never occur as a hi class. - case Memory: - case X87: - assert(0 && "Invalid classification for hi word."); - - case ComplexX87: // Previously handled. - case NoClass: break; - - case Integer: - ResType = llvm::StructType::get(ResType, llvm::Type::Int64Ty, NULL); - break; - case SSE: - ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL); - break; - - // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte - // is passed in the upper half of the last used SSE register. - // - // SSEUP should always be preceeded by SSE, just widen. - case SSEUp: - assert(Lo == SSE && "Unexpected SSEUp classification."); - ResType = llvm::VectorType::get(llvm::Type::DoubleTy, 2); - break; - - // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is - // returned together with the previous X87 value in %st0. - case X87Up: - // If X87Up is preceeded by X87, we don't need to do - // anything. However, in some cases with unions it may not be - // preceeded by X87. In such situations we follow gcc and pass the - // extra bits in an SSE reg. - if (Lo != X87) - ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL); - break; - } - - return getCoerceResult(RetTy, ResType, Context); -} - -ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context, - unsigned &neededInt, - unsigned &neededSSE) const { - X86_64ABIInfo::Class Lo, Hi; - classify(Ty, Context, 0, Lo, Hi); - - // Check some invariants. - // FIXME: Enforce these by construction. - assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); - assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); - assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); - - neededInt = 0; - neededSSE = 0; - const llvm::Type *ResType = 0; - switch (Lo) { - case NoClass: - return ABIArgInfo::getIgnore(); - - // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument - // on the stack. - case Memory: - - // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or - // COMPLEX_X87, it is passed in memory. - case X87: - case ComplexX87: - return getIndirectResult(Ty, Context); - - case SSEUp: - case X87Up: - assert(0 && "Invalid classification for lo word."); - - // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next - // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 - // and %r9 is used. - case Integer: - ++neededInt; - ResType = llvm::Type::Int64Ty; - break; - - // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next - // available SSE register is used, the registers are taken in the - // order from %xmm0 to %xmm7. - case SSE: - ++neededSSE; - ResType = llvm::Type::DoubleTy; - break; - } - - switch (Hi) { - // Memory was handled previously, ComplexX87 and X87 should - // never occur as hi classes, and X87Up must be preceed by X87, - // which is passed in memory. - case Memory: - case X87: - case ComplexX87: - assert(0 && "Invalid classification for hi word."); - break; - - case NoClass: break; - case Integer: - ResType = llvm::StructType::get(ResType, llvm::Type::Int64Ty, NULL); - ++neededInt; - break; - - // X87Up generally doesn't occur here (long double is passed in - // memory), except in situations involving unions. - case X87Up: - case SSE: - ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL); - ++neededSSE; - break; - - // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the - // eightbyte is passed in the upper half of the last used SSE - // register. - case SSEUp: - assert(Lo == SSE && "Unexpected SSEUp classification."); - ResType = llvm::VectorType::get(llvm::Type::DoubleTy, 2); - break; - } - - return getCoerceResult(Ty, ResType, Context); -} - -void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context); - - // Keep track of the number of assigned registers. - unsigned freeIntRegs = 6, freeSSERegs = 8; - - // If the return value is indirect, then the hidden argument is consuming one - // integer register. - if (FI.getReturnInfo().isIndirect()) - --freeIntRegs; - - // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers - // get assigned (in left-to-right order) for passing as follows... - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) { - unsigned neededInt, neededSSE; - it->info = classifyArgumentType(it->type, Context, neededInt, neededSSE); - - // AMD64-ABI 3.2.3p3: If there are no registers available for any - // eightbyte of an argument, the whole argument is passed on the - // stack. If registers have already been assigned for some - // eightbytes of such an argument, the assignments get reverted. - if (freeIntRegs >= neededInt && freeSSERegs >= neededSSE) { - freeIntRegs -= neededInt; - freeSSERegs -= neededSSE; - } else { - it->info = getIndirectResult(it->type, Context); - } - } -} - -static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr, - QualType Ty, - CodeGenFunction &CGF) { - llvm::Value *overflow_arg_area_p = - CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_p"); - llvm::Value *overflow_arg_area = - CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area"); - - // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16 - // byte boundary if alignment needed by type exceeds 8 byte boundary. - uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8; - if (Align > 8) { - // Note that we follow the ABI & gcc here, even though the type - // could in theory have an alignment greater than 16. This case - // shouldn't ever matter in practice. - - // overflow_arg_area = (overflow_arg_area + 15) & ~15; - llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, 15); - overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset); - llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(overflow_arg_area, - llvm::Type::Int64Ty); - llvm::Value *Mask = llvm::ConstantInt::get(llvm::Type::Int64Ty, ~15LL); - overflow_arg_area = - CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask), - overflow_arg_area->getType(), - "overflow_arg_area.align"); - } - - // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area. - const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); - llvm::Value *Res = - CGF.Builder.CreateBitCast(overflow_arg_area, - llvm::PointerType::getUnqual(LTy)); - - // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to: - // l->overflow_arg_area + sizeof(type). - // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to - // an 8 byte boundary. - - uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8; - llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, - (SizeInBytes + 7) & ~7); - overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset, - "overflow_arg_area.next"); - CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p); - - // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type. - return Res; -} - -llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - // Assume that va_list type is correct; should be pointer to LLVM type: - // struct { - // i32 gp_offset; - // i32 fp_offset; - // i8* overflow_arg_area; - // i8* reg_save_area; - // }; - unsigned neededInt, neededSSE; - ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), - neededInt, neededSSE); - - // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed - // in the registers. If not go to step 7. - if (!neededInt && !neededSSE) - return EmitVAArgFromMemory(VAListAddr, Ty, CGF); - - // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of - // general purpose registers needed to pass type and num_fp to hold - // the number of floating point registers needed. - - // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into - // registers. In the case: l->gp_offset > 48 - num_gp * 8 or - // l->fp_offset > 304 - num_fp * 16 go to step 7. - // - // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of - // register save space). - - llvm::Value *InRegs = 0; - llvm::Value *gp_offset_p = 0, *gp_offset = 0; - llvm::Value *fp_offset_p = 0, *fp_offset = 0; - if (neededInt) { - gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p"); - gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset"); - InRegs = - CGF.Builder.CreateICmpULE(gp_offset, - llvm::ConstantInt::get(llvm::Type::Int32Ty, - 48 - neededInt * 8), - "fits_in_gp"); - } - - if (neededSSE) { - fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, "fp_offset_p"); - fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset"); - llvm::Value *FitsInFP = - CGF.Builder.CreateICmpULE(fp_offset, - llvm::ConstantInt::get(llvm::Type::Int32Ty, - 176 - neededSSE * 16), - "fits_in_fp"); - InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP; - } - - llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); - llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem"); - llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); - CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); - - // Emit code to load the value if it was passed in registers. - - CGF.EmitBlock(InRegBlock); - - // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with - // an offset of l->gp_offset and/or l->fp_offset. This may require - // copying to a temporary location in case the parameter is passed - // in different register classes or requires an alignment greater - // than 8 for general purpose registers and 16 for XMM registers. - // - // FIXME: This really results in shameful code when we end up needing to - // collect arguments from different places; often what should result in a - // simple assembling of a structure from scattered addresses has many more - // loads than necessary. Can we clean this up? - const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); - llvm::Value *RegAddr = - CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3), - "reg_save_area"); - if (neededInt && neededSSE) { - // FIXME: Cleanup. - assert(AI.isCoerce() && "Unexpected ABI info for mixed regs"); - const llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType()); - llvm::Value *Tmp = CGF.CreateTempAlloca(ST); - assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs"); - const llvm::Type *TyLo = ST->getElementType(0); - const llvm::Type *TyHi = ST->getElementType(1); - assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) && - "Unexpected ABI info for mixed regs"); - const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo); - const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi); - llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); - llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); - llvm::Value *RegLoAddr = TyLo->isFloatingPoint() ? FPAddr : GPAddr; - llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr; - llvm::Value *V = - CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); - V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegHiAddr, PTyHi)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); - - RegAddr = CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(LTy)); - } else if (neededInt) { - RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); - RegAddr = CGF.Builder.CreateBitCast(RegAddr, - llvm::PointerType::getUnqual(LTy)); - } else { - if (neededSSE == 1) { - RegAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); - RegAddr = CGF.Builder.CreateBitCast(RegAddr, - llvm::PointerType::getUnqual(LTy)); - } else { - assert(neededSSE == 2 && "Invalid number of needed registers!"); - // SSE registers are spaced 16 bytes apart in the register save - // area, we need to collect the two eightbytes together. - llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset); - llvm::Value *RegAddrHi = - CGF.Builder.CreateGEP(RegAddrLo, - llvm::ConstantInt::get(llvm::Type::Int32Ty, 16)); - const llvm::Type *DblPtrTy = - llvm::PointerType::getUnqual(llvm::Type::DoubleTy); - const llvm::StructType *ST = llvm::StructType::get(llvm::Type::DoubleTy, - llvm::Type::DoubleTy, - NULL); - llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST); - V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo, - DblPtrTy)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); - V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrHi, - DblPtrTy)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); - RegAddr = CGF.Builder.CreateBitCast(Tmp, - llvm::PointerType::getUnqual(LTy)); - } - } - - // AMD64-ABI 3.5.7p5: Step 5. Set: - // l->gp_offset = l->gp_offset + num_gp * 8 - // l->fp_offset = l->fp_offset + num_fp * 16. - if (neededInt) { - llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, - neededInt * 8); - CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset), - gp_offset_p); - } - if (neededSSE) { - llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, - neededSSE * 16); - CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset), - fp_offset_p); - } - CGF.EmitBranch(ContBlock); - - // Emit code to load the value if it was passed in memory. - - CGF.EmitBlock(InMemBlock); - llvm::Value *MemAddr = EmitVAArgFromMemory(VAListAddr, Ty, CGF); - - // Return the appropriate result. - - CGF.EmitBlock(ContBlock); - llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(), - "vaarg.addr"); - ResAddr->reserveOperandSpace(2); - ResAddr->addIncoming(RegAddr, InRegBlock); - ResAddr->addIncoming(MemAddr, InMemBlock); - - return ResAddr; -} - -// ABI Info for PIC16 -class PIC16ABIInfo : public ABIInfo { - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type, Context); - } - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; - -}; - -ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else { - return ABIArgInfo::getDirect(); - } -} - -ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context) const { - return ABIArgInfo::getDirect(); -} - -llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - return 0; -} - -class ARMABIInfo : public ABIInfo { - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const; - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; - -void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) { - it->info = classifyArgumentType(it->type, Context); - } -} - -ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context) const { - if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { - return ABIArgInfo::getDirect(); - } - // FIXME: This is kind of nasty... but there isn't much choice because the ARM - // backend doesn't support byval. - // FIXME: This doesn't handle alignment > 64 bits. - const llvm::Type* ElemTy; - unsigned SizeRegs; - if (Context.getTypeAlign(Ty) > 32) { - ElemTy = llvm::Type::Int64Ty; - SizeRegs = (Context.getTypeSize(Ty) + 63) / 64; - } else { - ElemTy = llvm::Type::Int32Ty; - SizeRegs = (Context.getTypeSize(Ty) + 31) / 32; - } - std::vector<const llvm::Type*> LLVMFields; - LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs)); - const llvm::Type* STy = llvm::StructType::get(LLVMFields, true); - return ABIArgInfo::getCoerce(STy); -} - -ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - // Aggregates <= 4 bytes are returned in r0; other aggregates - // are returned indirectly. - uint64_t Size = Context.getTypeSize(RetTy); - if (Size <= 32) - return ABIArgInfo::getCoerce(llvm::Type::Int32Ty); - return ABIArgInfo::getIndirect(0); - } else { - return ABIArgInfo::getDirect(); - } -} - -llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - // FIXME: Need to handle alignment - const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); - const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); - - CGBuilderTy &Builder = CGF.Builder; - llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, - "ap"); - llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); - llvm::Type *PTy = - llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); - llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); - - uint64_t Offset = - llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4); - llvm::Value *NextAddr = - Builder.CreateGEP(Addr, - llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset), - "ap.next"); - Builder.CreateStore(NextAddr, VAListAddrAsBPP); - - return AddrTyped; -} - -ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - return ABIArgInfo::getIndirect(0); - } else { - return ABIArgInfo::getDirect(); - } -} - -ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context) const { - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { - return ABIArgInfo::getIndirect(0); - } else { - return ABIArgInfo::getDirect(); - } -} - -llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - return 0; -} - -const ABIInfo &CodeGenTypes::getABIInfo() const { - if (TheABIInfo) - return *TheABIInfo; - - // For now we just cache this in the CodeGenTypes and don't bother - // to free it. - const char *TargetPrefix = getContext().Target.getTargetPrefix(); - if (strcmp(TargetPrefix, "x86") == 0) { - bool IsDarwin = strstr(getContext().Target.getTargetTriple(), "darwin"); - switch (getContext().Target.getPointerWidth(0)) { - case 32: - return *(TheABIInfo = new X86_32ABIInfo(Context, IsDarwin)); - case 64: - return *(TheABIInfo = new X86_64ABIInfo()); - } - } else if (strcmp(TargetPrefix, "arm") == 0) { - // FIXME: Support for OABI? - return *(TheABIInfo = new ARMABIInfo()); - } else if (strcmp(TargetPrefix, "pic16") == 0) { - return *(TheABIInfo = new PIC16ABIInfo()); - } - - return *(TheABIInfo = new DefaultABIInfo); -} - -/***/ - CGFunctionInfo::CGFunctionInfo(QualType ResTy, const llvm::SmallVector<QualType, 16> &ArgTys) { NumArgs = ArgTys.size(); @@ -1637,13 +270,7 @@ static void CreateCoercedStore(llvm::Value *Src, uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(DstTy); // If store is legal, just bitcast the src pointer. - if (SrcSize >= DstSize) { - // Generally SrcSize is never greater than DstSize, since this means we are - // losing bits. However, this can happen in cases where the structure has - // additional padding, for example due to a user specified alignment. - // - // FIXME: Assert that we aren't truncating non-padding bits when have access - // to that information. + if (SrcSize <= DstSize) { llvm::Value *Casted = CGF.Builder.CreateBitCast(DstPtr, llvm::PointerType::getUnqual(SrcTy)); // FIXME: Use better alignment / avoid requiring aligned store. @@ -1651,6 +278,13 @@ static void CreateCoercedStore(llvm::Value *Src, } else { // Otherwise do coercion through memory. This is stupid, but // simple. + + // Generally SrcSize is never greater than DstSize, since this means we are + // losing bits. However, this can happen in cases where the structure has + // additional padding, for example due to a user specified alignment. + // + // FIXME: Assert that we aren't truncating non-padding bits when have access + // to that information. llvm::Value *Tmp = CGF.CreateTempAlloca(SrcTy); CGF.Builder.CreateStore(Src, Tmp); llvm::Value *Casted = @@ -1751,6 +385,11 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, FuncAttrs |= llvm::Attribute::ReadOnly; } + if (CompileOpts.DisableRedZone) + FuncAttrs |= llvm::Attribute::NoRedZone; + if (CompileOpts.NoImplicitFloat) + FuncAttrs |= llvm::Attribute::NoImplicitFloat; + QualType RetTy = FI.getReturnType(); unsigned Index = 1; const ABIArgInfo &RetAI = FI.getReturnInfo(); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index bcad77b..29eaaad 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -232,7 +232,9 @@ const llvm::Type *CodeGenFunction::BuildByRefType(QualType Ty, Types[4] = PtrToInt8Ty; Types[5] = PtrToInt8Ty; } - // FIXME: Align this on at least an Align boundary. + // FIXME: Align this on at least an Align boundary, assert if we can't. + assert((Align <= unsigned(Target.getPointerAlign(0))/8) + && "Can't align more thqn pointer yet"); Types[needsCopyDispose*2 + 4] = LTy; return llvm::StructType::get(Types, false); } @@ -244,22 +246,22 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { QualType Ty = D.getType(); bool isByRef = D.hasAttr<BlocksAttr>(); bool needsDispose = false; + unsigned Align = 0; llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { if (!Target.useGlobalsForAutomaticVariables()) { // A normal fixed sized variable becomes an alloca in the entry block. const llvm::Type *LTy = ConvertTypeForMem(Ty); + Align = getContext().getDeclAlignInBytes(&D); if (isByRef) - LTy = BuildByRefType(Ty, getContext().getDeclAlignInBytes(&D)); + LTy = BuildByRefType(Ty, Align); llvm::AllocaInst *Alloc = CreateTempAlloca(LTy); Alloc->setName(D.getNameAsString().c_str()); if (isByRef) - Alloc->setAlignment(std::max(getContext().getDeclAlignInBytes(&D), - unsigned(Target.getPointerAlign(0) / 8))); - else - Alloc->setAlignment(getContext().getDeclAlignInBytes(&D)); + Align = std::max(Align, unsigned(Target.getPointerAlign(0) / 8)); + Alloc->setAlignment(Align); DeclPtr = Alloc; } else { // Targets that don't support recursion emit locals as globals. @@ -401,11 +403,12 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { if (flags & BLOCK_HAS_COPY_DISPOSE) { BlockHasCopyDispose = true; llvm::Value *copy_helper = Builder.CreateStructGEP(DeclPtr, 4); - Builder.CreateStore(BuildbyrefCopyHelper(DeclPtr->getType(), flag), + Builder.CreateStore(BuildbyrefCopyHelper(DeclPtr->getType(), flag, Align), copy_helper); llvm::Value *destroy_helper = Builder.CreateStructGEP(DeclPtr, 5); - Builder.CreateStore(BuildbyrefDestroyHelper(DeclPtr->getType(), flag), + Builder.CreateStore(BuildbyrefDestroyHelper(DeclPtr->getType(), flag, + Align), destroy_helper); } } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 8d903d9..4268ae3 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -263,17 +263,21 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) { llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond()); Builder.CreateCondBr(Cond, LHSBlock, RHSBlock); + CGF.PushConditionalTempDestruction(); CGF.EmitBlock(LHSBlock); // Handle the GNU extension for missing LHS. assert(E->getLHS() && "Must have LHS for aggregate value"); Visit(E->getLHS()); + CGF.PopConditionalTempDestruction(); CGF.EmitBranch(ContBlock); + CGF.PushConditionalTempDestruction(); CGF.EmitBlock(RHSBlock); Visit(E->getRHS()); + CGF.PopConditionalTempDestruction(); CGF.EmitBranch(ContBlock); CGF.EmitBlock(ContBlock); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 950e9e5..ed18d32 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1290,8 +1290,10 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getFalse(), *PI); + CGF.PushConditionalTempDestruction(); CGF.EmitBlock(RHSBlock); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); + CGF.PopConditionalTempDestruction(); // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); @@ -1335,10 +1337,14 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getTrue(), *PI); + CGF.PushConditionalTempDestruction(); + // Emit the RHS condition as a bool value. CGF.EmitBlock(RHSBlock); Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); + CGF.PopConditionalTempDestruction(); + // Reaquire the RHS block, as there may be subblocks inserted. RHSBlock = Builder.GetInsertBlock(); @@ -1446,7 +1452,8 @@ VisitConditionalOperator(const ConditionalOperator *E) { CGF.getContext().BoolTy); Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock); } - + + CGF.PushConditionalTempDestruction(); CGF.EmitBlock(LHSBlock); // Handle the GNU extension for missing LHS. @@ -1456,12 +1463,15 @@ VisitConditionalOperator(const ConditionalOperator *E) { else // Perform promotions, to handle cases like "short ?: int" LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType()); + CGF.PopConditionalTempDestruction(); LHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); + CGF.PushConditionalTempDestruction(); CGF.EmitBlock(RHSBlock); Value *RHS = Visit(E->getRHS()); + CGF.PopConditionalTempDestruction(); RHSBlock = Builder.GetInsertBlock(); CGF.EmitBranch(ContBlock); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 5e7eec9..a70f718 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -1544,14 +1544,8 @@ LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, const ObjCInterfaceDecl *OID, const ObjCIvarDecl *OIVD) { - for (ObjCInterfaceDecl::ivar_iterator IVI = OID->ivar_begin(), - IVE = OID->ivar_end(); IVI != IVE; ++IVI) - if (OIVD == *IVI) - return OID; - - // Also look in synthesized ivars. llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; - Context.CollectSynthesizedIvars(OID, Ivars); + Context.ShallowCollectObjCIvars(OID, Ivars); for (unsigned k = 0, e = Ivars.size(); k != e; ++k) { if (OIVD == Ivars[k]) return OID; diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 8f1404d..75755ec 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -47,14 +47,8 @@ static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, // ASTContext::getObjCLayout is implemented. This should be fixed to // get the information from the layout directly. Index = 0; - for (ObjCInterfaceDecl::ivar_iterator IVI = OID->ivar_begin(), - IVE = OID->ivar_end(); IVI != IVE; ++IVI, ++Index) - if (OIVD == *IVI) - return OID; - - // Also look in synthesized ivars. llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; - Context.CollectSynthesizedIvars(OID, Ivars); + Context.ShallowCollectObjCIvars(OID, Ivars); for (unsigned k = 0, e = Ivars.size(); k != e; ++k) { if (OIVD == Ivars[k]) return OID; @@ -908,15 +902,6 @@ protected: unsigned Align, bool AddToUsed); - /// GetNamedIvarList - Return the list of ivars in the interface - /// itself (not including super classes and not including unnamed - /// bitfields). - /// - /// For the non-fragile ABI, this also includes synthesized property - /// ivars. - void GetNamedIvarList(const ObjCInterfaceDecl *OID, - llvm::SmallVector<ObjCIvarDecl*, 16> &Res) const; - CodeGen::RValue EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, llvm::Value *Sel, @@ -2198,10 +2183,13 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, const_cast<ObjCInterfaceDecl*>(ID->getClassInterface()); llvm::SmallVector<ObjCIvarDecl*, 16> OIvars; - GetNamedIvarList(OID, OIvars); + CGM.getContext().ShallowCollectObjCIvars(OID, OIvars); for (unsigned i = 0, e = OIvars.size(); i != e; ++i) { ObjCIvarDecl *IVD = OIvars[i]; + // Ignore unnamed bit-fields. + if (!IVD->getDeclName()) + continue; Ivar[0] = GetMethodVarName(IVD->getIdentifier()); Ivar[1] = GetMethodVarType(IVD); Ivar[2] = llvm::ConstantInt::get(ObjCTypes.IntTy, @@ -4696,25 +4684,6 @@ llvm::Constant * CGObjCNonFragileABIMac::EmitIvarOffsetVar( /// } /// -void CGObjCCommonMac::GetNamedIvarList(const ObjCInterfaceDecl *OID, - llvm::SmallVector<ObjCIvarDecl*, 16> &Res) const { - for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), - E = OID->ivar_end(); I != E; ++I) { - // Ignore unnamed bit-fields. - if (!(*I)->getDeclName()) - continue; - - Res.push_back(*I); - } - - // Also save synthesize ivars. - // FIXME. Why can't we just use passed in Res small vector? - llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; - CGM.getContext().CollectSynthesizedIvars(OID, Ivars); - for (unsigned k = 0, e = Ivars.size(); k != e; ++k) - Res.push_back(Ivars[k]); -} - llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( const ObjCImplementationDecl *ID) { @@ -4727,10 +4696,13 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( // Collect declared and synthesized ivars in a small vector. llvm::SmallVector<ObjCIvarDecl*, 16> OIvars; - GetNamedIvarList(OID, OIvars); + CGM.getContext().ShallowCollectObjCIvars(OID, OIvars); for (unsigned i = 0, e = OIvars.size(); i != e; ++i) { ObjCIvarDecl *IVD = OIvars[i]; + // Ignore unnamed bit-fields. + if (!IVD->getDeclName()) + continue; Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), IVD, ComputeIvarBaseOffset(CGM, ID, IVD)); Ivar[1] = GetMethodVarName(IVD->getIdentifier()); diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index d6c46a8..c206a3b 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -5,6 +5,7 @@ add_clang_library(clangCodeGen CGBlocks.cpp CGCall.cpp CGCXX.cpp + CGCXXTemp.cpp CGDebugInfo.cpp CGDecl.cpp CGExprAgg.cpp @@ -21,4 +22,5 @@ add_clang_library(clangCodeGen CodeGenTypes.cpp Mangle.cpp ModuleBuilder.cpp + TargetABIInfo.cpp ) diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index c91a052..72c4aa4 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -160,6 +160,20 @@ public: /// this behavior for branches? void EmitBranchThroughCleanup(llvm::BasicBlock *Dest); + /// PushConditionalTempDestruction - Should be called before a conditional + /// part of an expression is emitted. For example, before the RHS of the + /// expression below is emitted: + /// + /// b && f(T()); + /// + /// This is used to make sure that any temporaryes created in the conditional + /// branch are only destroyed if the branch is taken. + void PushConditionalTempDestruction(); + + /// PopConditionalTempDestruction - Should be called after a conditional + /// part of an expression has been emitted. + void PopConditionalTempDestruction(); + private: CGDebugInfo* DebugInfo; @@ -263,6 +277,11 @@ private: }; llvm::SmallVector<CXXLiveTemporaryInfo, 4> LiveTemporaries; + + /// ConditionalTempDestructionStack - Contains the number of live temporaries + /// when PushConditionalTempDestruction was called. This is used so that + /// we know how many temporaries were created by a certain expression. + llvm::SmallVector<size_t, 4> ConditionalTempDestructionStack; public: CodeGenFunction(CodeGenModule &cgm); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index b69301e..5c12c81 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -298,7 +298,7 @@ void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, GV->setLinkage(llvm::Function::InternalLinkage); } else if (D->hasAttr<DLLExportAttr>()) { GV->setLinkage(llvm::Function::DLLExportLinkage); - } else if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakImportAttr>()) { + } else if (D->hasAttr<WeakAttr>()) { GV->setLinkage(llvm::Function::WeakAnyLinkage); } else if (Linkage == GVA_C99Inline) { // In C99 mode, 'inline' functions are guaranteed to have a strong @@ -853,7 +853,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->setLinkage(llvm::Function::DLLImportLinkage); else if (D->hasAttr<DLLExportAttr>()) GV->setLinkage(llvm::Function::DLLExportLinkage); - else if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakImportAttr>()) + else if (D->hasAttr<WeakAttr>()) GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); else if (!CompileOpts.NoCommon && (!D->hasExternalStorage() && !D->getInit())) @@ -891,8 +891,9 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end(); UI != E; ) { // TODO: Do invokes ever occur in C code? If so, we should handle them too. + unsigned OpNo = UI.getOperandNo(); llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*UI++); - if (!CI) continue; + if (!CI || OpNo != 0) continue; // If the return types don't match exactly, and if the call isn't dead, then // we can't transform this call. diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp new file mode 100644 index 0000000..573ffed --- /dev/null +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -0,0 +1,1379 @@ +//===---- TargetABIInfo.cpp - Encapsulate target ABI details ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These classes wrap the information about a call or function +// definition used to handle ABI compliancy. +// +//===----------------------------------------------------------------------===// + +#include "ABIInfo.h" +#include "CodeGenFunction.h" +#include "clang/AST/RecordLayout.h" +#include "llvm/Type.h" + +using namespace clang; +using namespace CodeGen; + +ABIInfo::~ABIInfo() {} + +void ABIArgInfo::dump() const { + fprintf(stderr, "(ABIArgInfo Kind="); + switch (TheKind) { + case Direct: + fprintf(stderr, "Direct"); + break; + case Ignore: + fprintf(stderr, "Ignore"); + break; + case Coerce: + fprintf(stderr, "Coerce Type="); + getCoerceToType()->print(llvm::errs()); + break; + case Indirect: + fprintf(stderr, "Indirect Align=%d", getIndirectAlign()); + break; + case Expand: + fprintf(stderr, "Expand"); + break; + } + fprintf(stderr, ")\n"); +} + +static bool isEmptyRecord(ASTContext &Context, QualType T); + +/// isEmptyField - Return true iff a the field is "empty", that is it +/// is an unnamed bit-field or an (array of) empty record(s). +static bool isEmptyField(ASTContext &Context, const FieldDecl *FD) { + if (FD->isUnnamedBitfield()) + return true; + + QualType FT = FD->getType(); + // Constant arrays of empty records count as empty, strip them off. + while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) + FT = AT->getElementType(); + + return isEmptyRecord(Context, FT); +} + +/// isEmptyRecord - Return true iff a structure contains only empty +/// fields. Note that a structure with a flexible array member is not +/// considered empty. +static bool isEmptyRecord(ASTContext &Context, QualType T) { + const RecordType *RT = T->getAsRecordType(); + if (!RT) + return 0; + const RecordDecl *RD = RT->getDecl(); + if (RD->hasFlexibleArrayMember()) + return false; + for (RecordDecl::field_iterator i = RD->field_begin(Context), + e = RD->field_end(Context); i != e; ++i) + if (!isEmptyField(Context, *i)) + return false; + return true; +} + +/// isSingleElementStruct - Determine if a structure is a "single +/// element struct", i.e. it has exactly one non-empty field or +/// exactly one field which is itself a single element +/// struct. Structures with flexible array members are never +/// considered single element structs. +/// +/// \return The field declaration for the single non-empty field, if +/// it exists. +static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { + const RecordType *RT = T->getAsStructureType(); + if (!RT) + return 0; + + const RecordDecl *RD = RT->getDecl(); + if (RD->hasFlexibleArrayMember()) + return 0; + + const Type *Found = 0; + for (RecordDecl::field_iterator i = RD->field_begin(Context), + e = RD->field_end(Context); i != e; ++i) { + const FieldDecl *FD = *i; + QualType FT = FD->getType(); + + // Ignore empty fields. + if (isEmptyField(Context, FD)) + continue; + + // If we already found an element then this isn't a single-element + // struct. + if (Found) + return 0; + + // Treat single element arrays as the element. + while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { + if (AT->getSize().getZExtValue() != 1) + break; + FT = AT->getElementType(); + } + + if (!CodeGenFunction::hasAggregateLLVMType(FT)) { + Found = FT.getTypePtr(); + } else { + Found = isSingleElementStruct(FT, Context); + if (!Found) + return 0; + } + } + + return Found; +} + +static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) { + if (!Ty->getAsBuiltinType() && !Ty->isPointerType()) + return false; + + uint64_t Size = Context.getTypeSize(Ty); + return Size == 32 || Size == 64; +} + +static bool areAllFields32Or64BitBasicType(const RecordDecl *RD, + ASTContext &Context) { + for (RecordDecl::field_iterator i = RD->field_begin(Context), + e = RD->field_end(Context); i != e; ++i) { + const FieldDecl *FD = *i; + + if (!is32Or64BitBasicType(FD->getType(), Context)) + return false; + + // FIXME: Reject bit-fields wholesale; there are two problems, we don't know + // how to expand them yet, and the predicate for telling if a bitfield still + // counts as "basic" is more complicated than what we were doing previously. + if (FD->isBitField()) + return false; + } + + return true; +} + +namespace { +/// DefaultABIInfo - The default implementation for ABI specific +/// details. This implementation provides information which results in +/// self-consistent and sensible LLVM IR generation, but does not +/// conform to any particular ABI. +class DefaultABIInfo : public ABIInfo { + ABIArgInfo classifyReturnType(QualType RetTy, + ASTContext &Context) const; + + ABIArgInfo classifyArgumentType(QualType RetTy, + ASTContext &Context) const; + + virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type, Context); + } + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + +/// X86_32ABIInfo - The X86-32 ABI information. +class X86_32ABIInfo : public ABIInfo { + ASTContext &Context; + bool IsDarwin; + + static bool isRegisterSize(unsigned Size) { + return (Size == 8 || Size == 16 || Size == 32 || Size == 64); + } + + static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context); + +public: + ABIArgInfo classifyReturnType(QualType RetTy, + ASTContext &Context) const; + + ABIArgInfo classifyArgumentType(QualType RetTy, + ASTContext &Context) const; + + virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type, Context); + } + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; + + X86_32ABIInfo(ASTContext &Context, bool d) + : ABIInfo(), Context(Context), IsDarwin(d) {} +}; +} + + +/// shouldReturnTypeInRegister - Determine if the given type should be +/// passed in a register (for the Darwin ABI). +bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, + ASTContext &Context) { + uint64_t Size = Context.getTypeSize(Ty); + + // Type must be register sized. + if (!isRegisterSize(Size)) + return false; + + if (Ty->isVectorType()) { + // 64- and 128- bit vectors inside structures are not returned in + // registers. + if (Size == 64 || Size == 128) + return false; + + return true; + } + + // If this is a builtin, pointer, or complex type, it is ok. + if (Ty->getAsBuiltinType() || Ty->isPointerType() || Ty->isAnyComplexType()) + return true; + + // Arrays are treated like records. + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) + return shouldReturnTypeInRegister(AT->getElementType(), Context); + + // Otherwise, it must be a record type. + const RecordType *RT = Ty->getAsRecordType(); + if (!RT) return false; + + // Structure types are passed in register if all fields would be + // passed in a register. + for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(Context), + e = RT->getDecl()->field_end(Context); i != e; ++i) { + const FieldDecl *FD = *i; + + // Empty fields are ignored. + if (isEmptyField(Context, FD)) + continue; + + // Check fields recursively. + if (!shouldReturnTypeInRegister(FD->getType(), Context)) + return false; + } + + return true; +} + +ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, + ASTContext &Context) const { + if (RetTy->isVoidType()) { + return ABIArgInfo::getIgnore(); + } else if (const VectorType *VT = RetTy->getAsVectorType()) { + // On Darwin, some vectors are returned in registers. + if (IsDarwin) { + uint64_t Size = Context.getTypeSize(RetTy); + + // 128-bit vectors are a special case; they are returned in + // registers and we need to make sure to pick a type the LLVM + // backend will like. + if (Size == 128) + return ABIArgInfo::getCoerce(llvm::VectorType::get(llvm::Type::Int64Ty, + 2)); + + // Always return in register if it fits in a general purpose + // register, or if it is 64 bits and has a single element. + if ((Size == 8 || Size == 16 || Size == 32) || + (Size == 64 && VT->getNumElements() == 1)) + return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size)); + + return ABIArgInfo::getIndirect(0); + } + + return ABIArgInfo::getDirect(); + } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { + // Structures with flexible arrays are always indirect. + if (const RecordType *RT = RetTy->getAsStructureType()) + if (RT->getDecl()->hasFlexibleArrayMember()) + return ABIArgInfo::getIndirect(0); + + // Outside of Darwin, structs and unions are always indirect. + if (!IsDarwin && !RetTy->isAnyComplexType()) + return ABIArgInfo::getIndirect(0); + + // Classify "single element" structs as their element type. + if (const Type *SeltTy = isSingleElementStruct(RetTy, Context)) { + if (const BuiltinType *BT = SeltTy->getAsBuiltinType()) { + if (BT->isIntegerType()) { + // We need to use the size of the structure, padding + // bit-fields can adjust that to be larger than the single + // element type. + uint64_t Size = Context.getTypeSize(RetTy); + return ABIArgInfo::getCoerce(llvm::IntegerType::get((unsigned) Size)); + } else if (BT->getKind() == BuiltinType::Float) { + assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && + "Unexpect single element structure size!"); + return ABIArgInfo::getCoerce(llvm::Type::FloatTy); + } else if (BT->getKind() == BuiltinType::Double) { + assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && + "Unexpect single element structure size!"); + return ABIArgInfo::getCoerce(llvm::Type::DoubleTy); + } + } else if (SeltTy->isPointerType()) { + // FIXME: It would be really nice if this could come out as the proper + // pointer type. + llvm::Type *PtrTy = + llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + return ABIArgInfo::getCoerce(PtrTy); + } else if (SeltTy->isVectorType()) { + // 64- and 128-bit vectors are never returned in a + // register when inside a structure. + uint64_t Size = Context.getTypeSize(RetTy); + if (Size == 64 || Size == 128) + return ABIArgInfo::getIndirect(0); + + return classifyReturnType(QualType(SeltTy, 0), Context); + } + } + + // Small structures which are register sized are generally returned + // in a register. + if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context)) { + uint64_t Size = Context.getTypeSize(RetTy); + return ABIArgInfo::getCoerce(llvm::IntegerType::get(Size)); + } + + return ABIArgInfo::getIndirect(0); + } else { + return ABIArgInfo::getDirect(); + } +} + +ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, + ASTContext &Context) const { + // FIXME: Set alignment on indirect arguments. + if (CodeGenFunction::hasAggregateLLVMType(Ty)) { + // Structures with flexible arrays are always indirect. + if (const RecordType *RT = Ty->getAsStructureType()) + if (RT->getDecl()->hasFlexibleArrayMember()) + return ABIArgInfo::getIndirect(0); + + // Ignore empty structs. + uint64_t Size = Context.getTypeSize(Ty); + if (Ty->isStructureType() && Size == 0) + return ABIArgInfo::getIgnore(); + + // Expand structs with size <= 128-bits which consist only of + // basic types (int, long long, float, double, xxx*). This is + // non-recursive and does not ignore empty fields. + if (const RecordType *RT = Ty->getAsStructureType()) { + if (Context.getTypeSize(Ty) <= 4*32 && + areAllFields32Or64BitBasicType(RT->getDecl(), Context)) + return ABIArgInfo::getExpand(); + } + + return ABIArgInfo::getIndirect(0); + } else { + return ABIArgInfo::getDirect(); + } +} + +llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); + + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, + "ap"); + llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + llvm::Type *PTy = + llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); + llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); + + uint64_t Offset = + llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4); + llvm::Value *NextAddr = + Builder.CreateGEP(Addr, + llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset), + "ap.next"); + Builder.CreateStore(NextAddr, VAListAddrAsBPP); + + return AddrTyped; +} + +namespace { +/// X86_64ABIInfo - The X86_64 ABI information. +class X86_64ABIInfo : public ABIInfo { + enum Class { + Integer = 0, + SSE, + SSEUp, + X87, + X87Up, + ComplexX87, + NoClass, + Memory + }; + + /// merge - Implement the X86_64 ABI merging algorithm. + /// + /// Merge an accumulating classification \arg Accum with a field + /// classification \arg Field. + /// + /// \param Accum - The accumulating classification. This should + /// always be either NoClass or the result of a previous merge + /// call. In addition, this should never be Memory (the caller + /// should just return Memory for the aggregate). + Class merge(Class Accum, Class Field) const; + + /// classify - Determine the x86_64 register classes in which the + /// given type T should be passed. + /// + /// \param Lo - The classification for the parts of the type + /// residing in the low word of the containing object. + /// + /// \param Hi - The classification for the parts of the type + /// residing in the high word of the containing object. + /// + /// \param OffsetBase - The bit offset of this type in the + /// containing object. Some parameters are classified different + /// depending on whether they straddle an eightbyte boundary. + /// + /// If a word is unused its result will be NoClass; if a type should + /// be passed in Memory then at least the classification of \arg Lo + /// will be Memory. + /// + /// The \arg Lo class will be NoClass iff the argument is ignored. + /// + /// If the \arg Lo class is ComplexX87, then the \arg Hi class will + /// also be ComplexX87. + void classify(QualType T, ASTContext &Context, uint64_t OffsetBase, + Class &Lo, Class &Hi) const; + + /// getCoerceResult - Given a source type \arg Ty and an LLVM type + /// to coerce to, chose the best way to pass Ty in the same place + /// that \arg CoerceTo would be passed, but while keeping the + /// emitted code as simple as possible. + /// + /// FIXME: Note, this should be cleaned up to just take an enumeration of all + /// the ways we might want to pass things, instead of constructing an LLVM + /// type. This makes this code more explicit, and it makes it clearer that we + /// are also doing this for correctness in the case of passing scalar types. + ABIArgInfo getCoerceResult(QualType Ty, + const llvm::Type *CoerceTo, + ASTContext &Context) const; + + /// getIndirectResult - Give a source type \arg Ty, return a suitable result + /// such that the argument will be passed in memory. + ABIArgInfo getIndirectResult(QualType Ty, + ASTContext &Context) const; + + ABIArgInfo classifyReturnType(QualType RetTy, + ASTContext &Context) const; + + ABIArgInfo classifyArgumentType(QualType Ty, + ASTContext &Context, + unsigned &neededInt, + unsigned &neededSSE) const; + +public: + virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const; + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; +} + +X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, + Class Field) const { + // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is + // classified recursively so that always two fields are + // considered. The resulting class is calculated according to + // the classes of the fields in the eightbyte: + // + // (a) If both classes are equal, this is the resulting class. + // + // (b) If one of the classes is NO_CLASS, the resulting class is + // the other class. + // + // (c) If one of the classes is MEMORY, the result is the MEMORY + // class. + // + // (d) If one of the classes is INTEGER, the result is the + // INTEGER. + // + // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class, + // MEMORY is used as class. + // + // (f) Otherwise class SSE is used. + + // Accum should never be memory (we should have returned) or + // ComplexX87 (because this cannot be passed in a structure). + assert((Accum != Memory && Accum != ComplexX87) && + "Invalid accumulated classification during merge."); + if (Accum == Field || Field == NoClass) + return Accum; + else if (Field == Memory) + return Memory; + else if (Accum == NoClass) + return Field; + else if (Accum == Integer || Field == Integer) + return Integer; + else if (Field == X87 || Field == X87Up || Field == ComplexX87 || + Accum == X87 || Accum == X87Up) + return Memory; + else + return SSE; +} + +void X86_64ABIInfo::classify(QualType Ty, + ASTContext &Context, + uint64_t OffsetBase, + Class &Lo, Class &Hi) const { + // FIXME: This code can be simplified by introducing a simple value class for + // Class pairs with appropriate constructor methods for the various + // situations. + + // FIXME: Some of the split computations are wrong; unaligned vectors + // shouldn't be passed in registers for example, so there is no chance they + // can straddle an eightbyte. Verify & simplify. + + Lo = Hi = NoClass; + + Class &Current = OffsetBase < 64 ? Lo : Hi; + Current = Memory; + + if (const BuiltinType *BT = Ty->getAsBuiltinType()) { + BuiltinType::Kind k = BT->getKind(); + + if (k == BuiltinType::Void) { + Current = NoClass; + } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { + Lo = Integer; + Hi = Integer; + } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) { + Current = Integer; + } else if (k == BuiltinType::Float || k == BuiltinType::Double) { + Current = SSE; + } else if (k == BuiltinType::LongDouble) { + Lo = X87; + Hi = X87Up; + } + // FIXME: _Decimal32 and _Decimal64 are SSE. + // FIXME: _float128 and _Decimal128 are (SSE, SSEUp). + } else if (const EnumType *ET = Ty->getAsEnumType()) { + // Classify the underlying integer type. + classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi); + } else if (Ty->hasPointerRepresentation()) { + Current = Integer; + } else if (const VectorType *VT = Ty->getAsVectorType()) { + uint64_t Size = Context.getTypeSize(VT); + if (Size == 32) { + // gcc passes all <4 x char>, <2 x short>, <1 x int>, <1 x + // float> as integer. + Current = Integer; + + // If this type crosses an eightbyte boundary, it should be + // split. + uint64_t EB_Real = (OffsetBase) / 64; + uint64_t EB_Imag = (OffsetBase + Size - 1) / 64; + if (EB_Real != EB_Imag) + Hi = Lo; + } else if (Size == 64) { + // gcc passes <1 x double> in memory. :( + if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double)) + return; + + // gcc passes <1 x long long> as INTEGER. + if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong)) + Current = Integer; + else + Current = SSE; + + // If this type crosses an eightbyte boundary, it should be + // split. + if (OffsetBase && OffsetBase != 64) + Hi = Lo; + } else if (Size == 128) { + Lo = SSE; + Hi = SSEUp; + } + } else if (const ComplexType *CT = Ty->getAsComplexType()) { + QualType ET = Context.getCanonicalType(CT->getElementType()); + + uint64_t Size = Context.getTypeSize(Ty); + if (ET->isIntegralType()) { + if (Size <= 64) + Current = Integer; + else if (Size <= 128) + Lo = Hi = Integer; + } else if (ET == Context.FloatTy) + Current = SSE; + else if (ET == Context.DoubleTy) + Lo = Hi = SSE; + else if (ET == Context.LongDoubleTy) + Current = ComplexX87; + + // If this complex type crosses an eightbyte boundary then it + // should be split. + uint64_t EB_Real = (OffsetBase) / 64; + uint64_t EB_Imag = (OffsetBase + Context.getTypeSize(ET)) / 64; + if (Hi == NoClass && EB_Real != EB_Imag) + Hi = Lo; + } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { + // Arrays are treated like structures. + + uint64_t Size = Context.getTypeSize(Ty); + + // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger + // than two eightbytes, ..., it has class MEMORY. + if (Size > 128) + return; + + // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned + // fields, it has class MEMORY. + // + // Only need to check alignment of array base. + if (OffsetBase % Context.getTypeAlign(AT->getElementType())) + return; + + // Otherwise implement simplified merge. We could be smarter about + // this, but it isn't worth it and would be harder to verify. + Current = NoClass; + uint64_t EltSize = Context.getTypeSize(AT->getElementType()); + uint64_t ArraySize = AT->getSize().getZExtValue(); + for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) { + Class FieldLo, FieldHi; + classify(AT->getElementType(), Context, Offset, FieldLo, FieldHi); + Lo = merge(Lo, FieldLo); + Hi = merge(Hi, FieldHi); + if (Lo == Memory || Hi == Memory) + break; + } + + // Do post merger cleanup (see below). Only case we worry about is Memory. + if (Hi == Memory) + Lo = Memory; + assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification."); + } else if (const RecordType *RT = Ty->getAsRecordType()) { + uint64_t Size = Context.getTypeSize(Ty); + + // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger + // than two eightbytes, ..., it has class MEMORY. + if (Size > 128) + return; + + const RecordDecl *RD = RT->getDecl(); + + // Assume variable sized types are passed in memory. + if (RD->hasFlexibleArrayMember()) + return; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // Reset Lo class, this will be recomputed. + Current = NoClass; + unsigned idx = 0; + for (RecordDecl::field_iterator i = RD->field_begin(Context), + e = RD->field_end(Context); i != e; ++i, ++idx) { + uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); + bool BitField = i->isBitField(); + + // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned + // fields, it has class MEMORY. + // + // Note, skip this test for bit-fields, see below. + if (!BitField && Offset % Context.getTypeAlign(i->getType())) { + Lo = Memory; + return; + } + + // Classify this field. + // + // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate + // exceeds a single eightbyte, each is classified + // separately. Each eightbyte gets initialized to class + // NO_CLASS. + Class FieldLo, FieldHi; + + // Bit-fields require special handling, they do not force the + // structure to be passed in memory even if unaligned, and + // therefore they can straddle an eightbyte. + if (BitField) { + // Ignore padding bit-fields. + if (i->isUnnamedBitfield()) + continue; + + uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); + uint64_t Size = i->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + + uint64_t EB_Lo = Offset / 64; + uint64_t EB_Hi = (Offset + Size - 1) / 64; + FieldLo = FieldHi = NoClass; + if (EB_Lo) { + assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes."); + FieldLo = NoClass; + FieldHi = Integer; + } else { + FieldLo = Integer; + FieldHi = EB_Hi ? Integer : NoClass; + } + } else + classify(i->getType(), Context, Offset, FieldLo, FieldHi); + Lo = merge(Lo, FieldLo); + Hi = merge(Hi, FieldHi); + if (Lo == Memory || Hi == Memory) + break; + } + + // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done: + // + // (a) If one of the classes is MEMORY, the whole argument is + // passed in memory. + // + // (b) If SSEUP is not preceeded by SSE, it is converted to SSE. + + // The first of these conditions is guaranteed by how we implement + // the merge (just bail). + // + // The second condition occurs in the case of unions; for example + // union { _Complex double; unsigned; }. + if (Hi == Memory) + Lo = Memory; + if (Hi == SSEUp && Lo != SSE) + Hi = SSE; + } +} + +ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty, + const llvm::Type *CoerceTo, + ASTContext &Context) const { + if (CoerceTo == llvm::Type::Int64Ty) { + // Integer and pointer types will end up in a general purpose + // register. + if (Ty->isIntegralType() || Ty->isPointerType()) + return ABIArgInfo::getDirect(); + + } else if (CoerceTo == llvm::Type::DoubleTy) { + // FIXME: It would probably be better to make CGFunctionInfo only map using + // canonical types than to canonize here. + QualType CTy = Context.getCanonicalType(Ty); + + // Float and double end up in a single SSE reg. + if (CTy == Context.FloatTy || CTy == Context.DoubleTy) + return ABIArgInfo::getDirect(); + + } + + return ABIArgInfo::getCoerce(CoerceTo); +} + +ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, + ASTContext &Context) const { + // If this is a scalar LLVM value then assume LLVM will pass it in the right + // place naturally. + if (!CodeGenFunction::hasAggregateLLVMType(Ty)) + return ABIArgInfo::getDirect(); + + // FIXME: Set alignment correctly. + return ABIArgInfo::getIndirect(0); +} + +ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy, + ASTContext &Context) const { + // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the + // classification algorithm. + X86_64ABIInfo::Class Lo, Hi; + classify(RetTy, Context, 0, Lo, Hi); + + // Check some invariants. + assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); + assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); + assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); + + const llvm::Type *ResType = 0; + switch (Lo) { + case NoClass: + return ABIArgInfo::getIgnore(); + + case SSEUp: + case X87Up: + assert(0 && "Invalid classification for lo word."); + + // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via + // hidden argument. + case Memory: + return getIndirectResult(RetTy, Context); + + // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next + // available register of the sequence %rax, %rdx is used. + case Integer: + ResType = llvm::Type::Int64Ty; break; + + // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next + // available SSE register of the sequence %xmm0, %xmm1 is used. + case SSE: + ResType = llvm::Type::DoubleTy; break; + + // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is + // returned on the X87 stack in %st0 as 80-bit x87 number. + case X87: + ResType = llvm::Type::X86_FP80Ty; break; + + // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real + // part of the value is returned in %st0 and the imaginary part in + // %st1. + case ComplexX87: + assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification."); + ResType = llvm::StructType::get(llvm::Type::X86_FP80Ty, + llvm::Type::X86_FP80Ty, + NULL); + break; + } + + switch (Hi) { + // Memory was handled previously and X87 should + // never occur as a hi class. + case Memory: + case X87: + assert(0 && "Invalid classification for hi word."); + + case ComplexX87: // Previously handled. + case NoClass: break; + + case Integer: + ResType = llvm::StructType::get(ResType, llvm::Type::Int64Ty, NULL); + break; + case SSE: + ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL); + break; + + // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte + // is passed in the upper half of the last used SSE register. + // + // SSEUP should always be preceeded by SSE, just widen. + case SSEUp: + assert(Lo == SSE && "Unexpected SSEUp classification."); + ResType = llvm::VectorType::get(llvm::Type::DoubleTy, 2); + break; + + // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is + // returned together with the previous X87 value in %st0. + case X87Up: + // If X87Up is preceeded by X87, we don't need to do + // anything. However, in some cases with unions it may not be + // preceeded by X87. In such situations we follow gcc and pass the + // extra bits in an SSE reg. + if (Lo != X87) + ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL); + break; + } + + return getCoerceResult(RetTy, ResType, Context); +} + +ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context, + unsigned &neededInt, + unsigned &neededSSE) const { + X86_64ABIInfo::Class Lo, Hi; + classify(Ty, Context, 0, Lo, Hi); + + // Check some invariants. + // FIXME: Enforce these by construction. + assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); + assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); + assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); + + neededInt = 0; + neededSSE = 0; + const llvm::Type *ResType = 0; + switch (Lo) { + case NoClass: + return ABIArgInfo::getIgnore(); + + // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument + // on the stack. + case Memory: + + // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or + // COMPLEX_X87, it is passed in memory. + case X87: + case ComplexX87: + return getIndirectResult(Ty, Context); + + case SSEUp: + case X87Up: + assert(0 && "Invalid classification for lo word."); + + // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next + // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 + // and %r9 is used. + case Integer: + ++neededInt; + ResType = llvm::Type::Int64Ty; + break; + + // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next + // available SSE register is used, the registers are taken in the + // order from %xmm0 to %xmm7. + case SSE: + ++neededSSE; + ResType = llvm::Type::DoubleTy; + break; + } + + switch (Hi) { + // Memory was handled previously, ComplexX87 and X87 should + // never occur as hi classes, and X87Up must be preceed by X87, + // which is passed in memory. + case Memory: + case X87: + case ComplexX87: + assert(0 && "Invalid classification for hi word."); + break; + + case NoClass: break; + case Integer: + ResType = llvm::StructType::get(ResType, llvm::Type::Int64Ty, NULL); + ++neededInt; + break; + + // X87Up generally doesn't occur here (long double is passed in + // memory), except in situations involving unions. + case X87Up: + case SSE: + ResType = llvm::StructType::get(ResType, llvm::Type::DoubleTy, NULL); + ++neededSSE; + break; + + // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the + // eightbyte is passed in the upper half of the last used SSE + // register. + case SSEUp: + assert(Lo == SSE && "Unexpected SSEUp classification."); + ResType = llvm::VectorType::get(llvm::Type::DoubleTy, 2); + break; + } + + return getCoerceResult(Ty, ResType, Context); +} + +void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context); + + // Keep track of the number of assigned registers. + unsigned freeIntRegs = 6, freeSSERegs = 8; + + // If the return value is indirect, then the hidden argument is consuming one + // integer register. + if (FI.getReturnInfo().isIndirect()) + --freeIntRegs; + + // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers + // get assigned (in left-to-right order) for passing as follows... + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) { + unsigned neededInt, neededSSE; + it->info = classifyArgumentType(it->type, Context, neededInt, neededSSE); + + // AMD64-ABI 3.2.3p3: If there are no registers available for any + // eightbyte of an argument, the whole argument is passed on the + // stack. If registers have already been assigned for some + // eightbytes of such an argument, the assignments get reverted. + if (freeIntRegs >= neededInt && freeSSERegs >= neededSSE) { + freeIntRegs -= neededInt; + freeSSERegs -= neededSSE; + } else { + it->info = getIndirectResult(it->type, Context); + } + } +} + +static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr, + QualType Ty, + CodeGenFunction &CGF) { + llvm::Value *overflow_arg_area_p = + CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_p"); + llvm::Value *overflow_arg_area = + CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area"); + + // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16 + // byte boundary if alignment needed by type exceeds 8 byte boundary. + uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8; + if (Align > 8) { + // Note that we follow the ABI & gcc here, even though the type + // could in theory have an alignment greater than 16. This case + // shouldn't ever matter in practice. + + // overflow_arg_area = (overflow_arg_area + 15) & ~15; + llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, 15); + overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset); + llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(overflow_arg_area, + llvm::Type::Int64Ty); + llvm::Value *Mask = llvm::ConstantInt::get(llvm::Type::Int64Ty, ~15LL); + overflow_arg_area = + CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask), + overflow_arg_area->getType(), + "overflow_arg_area.align"); + } + + // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area. + const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); + llvm::Value *Res = + CGF.Builder.CreateBitCast(overflow_arg_area, + llvm::PointerType::getUnqual(LTy)); + + // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to: + // l->overflow_arg_area + sizeof(type). + // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to + // an 8 byte boundary. + + uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8; + llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, + (SizeInBytes + 7) & ~7); + overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset, + "overflow_arg_area.next"); + CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p); + + // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type. + return Res; +} + +llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + // Assume that va_list type is correct; should be pointer to LLVM type: + // struct { + // i32 gp_offset; + // i32 fp_offset; + // i8* overflow_arg_area; + // i8* reg_save_area; + // }; + unsigned neededInt, neededSSE; + ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), + neededInt, neededSSE); + + // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed + // in the registers. If not go to step 7. + if (!neededInt && !neededSSE) + return EmitVAArgFromMemory(VAListAddr, Ty, CGF); + + // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of + // general purpose registers needed to pass type and num_fp to hold + // the number of floating point registers needed. + + // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into + // registers. In the case: l->gp_offset > 48 - num_gp * 8 or + // l->fp_offset > 304 - num_fp * 16 go to step 7. + // + // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of + // register save space). + + llvm::Value *InRegs = 0; + llvm::Value *gp_offset_p = 0, *gp_offset = 0; + llvm::Value *fp_offset_p = 0, *fp_offset = 0; + if (neededInt) { + gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p"); + gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset"); + InRegs = + CGF.Builder.CreateICmpULE(gp_offset, + llvm::ConstantInt::get(llvm::Type::Int32Ty, + 48 - neededInt * 8), + "fits_in_gp"); + } + + if (neededSSE) { + fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, "fp_offset_p"); + fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset"); + llvm::Value *FitsInFP = + CGF.Builder.CreateICmpULE(fp_offset, + llvm::ConstantInt::get(llvm::Type::Int32Ty, + 176 - neededSSE * 16), + "fits_in_fp"); + InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP; + } + + llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); + llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem"); + llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); + CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); + + // Emit code to load the value if it was passed in registers. + + CGF.EmitBlock(InRegBlock); + + // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with + // an offset of l->gp_offset and/or l->fp_offset. This may require + // copying to a temporary location in case the parameter is passed + // in different register classes or requires an alignment greater + // than 8 for general purpose registers and 16 for XMM registers. + // + // FIXME: This really results in shameful code when we end up needing to + // collect arguments from different places; often what should result in a + // simple assembling of a structure from scattered addresses has many more + // loads than necessary. Can we clean this up? + const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); + llvm::Value *RegAddr = + CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3), + "reg_save_area"); + if (neededInt && neededSSE) { + // FIXME: Cleanup. + assert(AI.isCoerce() && "Unexpected ABI info for mixed regs"); + const llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType()); + llvm::Value *Tmp = CGF.CreateTempAlloca(ST); + assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs"); + const llvm::Type *TyLo = ST->getElementType(0); + const llvm::Type *TyHi = ST->getElementType(1); + assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) && + "Unexpected ABI info for mixed regs"); + const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo); + const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi); + llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); + llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); + llvm::Value *RegLoAddr = TyLo->isFloatingPoint() ? FPAddr : GPAddr; + llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr; + llvm::Value *V = + CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo)); + CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); + V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegHiAddr, PTyHi)); + CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); + + RegAddr = CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(LTy)); + } else if (neededInt) { + RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); + RegAddr = CGF.Builder.CreateBitCast(RegAddr, + llvm::PointerType::getUnqual(LTy)); + } else { + if (neededSSE == 1) { + RegAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); + RegAddr = CGF.Builder.CreateBitCast(RegAddr, + llvm::PointerType::getUnqual(LTy)); + } else { + assert(neededSSE == 2 && "Invalid number of needed registers!"); + // SSE registers are spaced 16 bytes apart in the register save + // area, we need to collect the two eightbytes together. + llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset); + llvm::Value *RegAddrHi = + CGF.Builder.CreateGEP(RegAddrLo, + llvm::ConstantInt::get(llvm::Type::Int32Ty, 16)); + const llvm::Type *DblPtrTy = + llvm::PointerType::getUnqual(llvm::Type::DoubleTy); + const llvm::StructType *ST = llvm::StructType::get(llvm::Type::DoubleTy, + llvm::Type::DoubleTy, + NULL); + llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST); + V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo, + DblPtrTy)); + CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); + V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrHi, + DblPtrTy)); + CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); + RegAddr = CGF.Builder.CreateBitCast(Tmp, + llvm::PointerType::getUnqual(LTy)); + } + } + + // AMD64-ABI 3.5.7p5: Step 5. Set: + // l->gp_offset = l->gp_offset + num_gp * 8 + // l->fp_offset = l->fp_offset + num_fp * 16. + if (neededInt) { + llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, + neededInt * 8); + CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset), + gp_offset_p); + } + if (neededSSE) { + llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::Int32Ty, + neededSSE * 16); + CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset), + fp_offset_p); + } + CGF.EmitBranch(ContBlock); + + // Emit code to load the value if it was passed in memory. + + CGF.EmitBlock(InMemBlock); + llvm::Value *MemAddr = EmitVAArgFromMemory(VAListAddr, Ty, CGF); + + // Return the appropriate result. + + CGF.EmitBlock(ContBlock); + llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(), + "vaarg.addr"); + ResAddr->reserveOperandSpace(2); + ResAddr->addIncoming(RegAddr, InRegBlock); + ResAddr->addIncoming(MemAddr, InMemBlock); + + return ResAddr; +} + +// ABI Info for PIC16 +class PIC16ABIInfo : public ABIInfo { + ABIArgInfo classifyReturnType(QualType RetTy, + ASTContext &Context) const; + + ABIArgInfo classifyArgumentType(QualType RetTy, + ASTContext &Context) const; + + virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type, Context); + } + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; + +}; + +ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy, + ASTContext &Context) const { + if (RetTy->isVoidType()) { + return ABIArgInfo::getIgnore(); + } else { + return ABIArgInfo::getDirect(); + } +} + +ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty, + ASTContext &Context) const { + return ABIArgInfo::getDirect(); +} + +llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + return 0; +} + +class ARMABIInfo : public ABIInfo { + ABIArgInfo classifyReturnType(QualType RetTy, + ASTContext &Context) const; + + ABIArgInfo classifyArgumentType(QualType RetTy, + ASTContext &Context) const; + + virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context) const; + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + +void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) { + it->info = classifyArgumentType(it->type, Context); + } +} + +ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, + ASTContext &Context) const { + if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { + return ABIArgInfo::getDirect(); + } + // FIXME: This is kind of nasty... but there isn't much choice because the ARM + // backend doesn't support byval. + // FIXME: This doesn't handle alignment > 64 bits. + const llvm::Type* ElemTy; + unsigned SizeRegs; + if (Context.getTypeAlign(Ty) > 32) { + ElemTy = llvm::Type::Int64Ty; + SizeRegs = (Context.getTypeSize(Ty) + 63) / 64; + } else { + ElemTy = llvm::Type::Int32Ty; + SizeRegs = (Context.getTypeSize(Ty) + 31) / 32; + } + std::vector<const llvm::Type*> LLVMFields; + LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs)); + const llvm::Type* STy = llvm::StructType::get(LLVMFields, true); + return ABIArgInfo::getCoerce(STy); +} + +ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, + ASTContext &Context) const { + if (RetTy->isVoidType()) { + return ABIArgInfo::getIgnore(); + } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { + // Aggregates <= 4 bytes are returned in r0; other aggregates + // are returned indirectly. + uint64_t Size = Context.getTypeSize(RetTy); + if (Size <= 32) + return ABIArgInfo::getCoerce(llvm::Type::Int32Ty); + return ABIArgInfo::getIndirect(0); + } else { + return ABIArgInfo::getDirect(); + } +} + +llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + // FIXME: Need to handle alignment + const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); + + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, + "ap"); + llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + llvm::Type *PTy = + llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); + llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); + + uint64_t Offset = + llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4); + llvm::Value *NextAddr = + Builder.CreateGEP(Addr, + llvm::ConstantInt::get(llvm::Type::Int32Ty, Offset), + "ap.next"); + Builder.CreateStore(NextAddr, VAListAddrAsBPP); + + return AddrTyped; +} + +ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy, + ASTContext &Context) const { + if (RetTy->isVoidType()) { + return ABIArgInfo::getIgnore(); + } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { + return ABIArgInfo::getIndirect(0); + } else { + return ABIArgInfo::getDirect(); + } +} + +ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, + ASTContext &Context) const { + if (CodeGenFunction::hasAggregateLLVMType(Ty)) { + return ABIArgInfo::getIndirect(0); + } else { + return ABIArgInfo::getDirect(); + } +} + +llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + return 0; +} + +const ABIInfo &CodeGenTypes::getABIInfo() const { + if (TheABIInfo) + return *TheABIInfo; + + // For now we just cache this in the CodeGenTypes and don't bother + // to free it. + const char *TargetPrefix = getContext().Target.getTargetPrefix(); + if (strcmp(TargetPrefix, "x86") == 0) { + bool IsDarwin = strstr(getContext().Target.getTargetTriple(), "darwin"); + switch (getContext().Target.getPointerWidth(0)) { + case 32: + return *(TheABIInfo = new X86_32ABIInfo(Context, IsDarwin)); + case 64: + return *(TheABIInfo = new X86_64ABIInfo()); + } + } else if (strcmp(TargetPrefix, "arm") == 0) { + // FIXME: Support for OABI? + return *(TheABIInfo = new ARMABIInfo()); + } else if (strcmp(TargetPrefix, "pic16") == 0) { + return *(TheABIInfo = new PIC16ABIInfo()); + } + + return *(TheABIInfo = new DefaultABIInfo); +} diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index eca6413..6b082c8 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -329,7 +329,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_msoft_float, options::OPT_mno_soft_float, false)) - CmdArgs.push_back("--soft-float"); + CmdArgs.push_back("--no-implicit-float"); // FIXME: Handle -mtune=. (void) Args.hasArg(options::OPT_mtune_EQ); @@ -505,6 +505,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fblocks=0"); } + // -fsigned-char/-funsigned-char default varies depending on platform; only + // pass if specified. + if (Arg *A = Args.getLastArg(options::OPT_fsigned_char, + options::OPT_funsigned_char)) { + if (A->getOption().matches(options::OPT_fsigned_char)) + CmdArgs.push_back("-fsigned-char"); + else + CmdArgs.push_back("-fsigned-char=0"); + } + // -fno-pascal-strings is default, only pass non-default. If the // -tool chain happened to translate to -mpascal-strings, we want to // -back translate here. @@ -539,6 +549,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fdiagnostics_show_option, options::OPT_fno_diagnostics_show_option)) CmdArgs.push_back("-fdiagnostics-show-option"); + if (!Args.hasFlag(options::OPT_fcolor_diagnostics, + options::OPT_fno_color_diagnostics)) + CmdArgs.push_back("-fno-color-diagnostics"); // -fdollars-in-identifiers default varies depending on platform and // language; only pass if specified. diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index e3a45d4..01729fa 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -23,8 +23,8 @@ namespace clang { // Append a #define line to Buf for Macro. Macro should be of the form XXX, // in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit // "#define XXX Y z W". To get a #define with no value, use "XXX=". -static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro, - const char *Command = "#define ") { +static void DefineBuiltinMacro(std::vector<char> &Buf, const char *Macro) { + const char *Command = "#define "; Buf.insert(Buf.end(), Command, Command+strlen(Command)); if (const char *Equal = strchr(Macro, '=')) { // Turn the = into ' '. @@ -367,7 +367,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, sprintf(MacroBuf, "__POINTER_WIDTH__=%d", (int)TI.getPointerWidth(0)); DefineBuiltinMacro(Buf, MacroBuf); - if (!TI.isCharSigned()) + if (!LangOpts.CharIsSigned) DefineBuiltinMacro(Buf, "__CHAR_UNSIGNED__"); // Define fixed-sized integer types for stdint.h @@ -403,11 +403,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // command line options or something. DefineBuiltinMacro(Buf, "__FINITE_MATH_ONLY__=0"); - if (LangOpts.Static) - DefineBuiltinMacro(Buf, "__STATIC__=1"); - else - DefineBuiltinMacro(Buf, "__DYNAMIC__=1"); - if (LangOpts.GNUInline) DefineBuiltinMacro(Buf, "__GNUC_GNU_INLINE__=1"); else diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 63e4337..87fc839 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1521,6 +1521,7 @@ bool PCHReader::ParseLanguageOptions( PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline); PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline); PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control); + PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed); if ((LangOpts.getGCMode() != 0) != (Record[Idx] != 0)) { Diag(diag::warn_pch_gc_mode) << (unsigned)Record[Idx] << LangOpts.getGCMode(); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 80e863b..765fecb 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -556,6 +556,8 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.NoInline); // Should __NO_INLINE__ be defined. Record.push_back(LangOpts.AccessControl); // Whether C++ access control should // be enabled. + Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or + // unsigned type Record.push_back(LangOpts.getGCMode()); Record.push_back(LangOpts.getVisibilityMode()); Record.push_back(LangOpts.InstantiationDepth); diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index f02d5d4..b9fe068 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -220,6 +220,7 @@ namespace { } virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, + DeclPtrTy IntfDecl, Declarator &D, ExprTy *BitfieldWidth, tok::ObjCKeywordKind visibility) { Out << __FUNCTION__ << "\n"; diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index b1c0533..6699c65 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -20,6 +20,20 @@ #include <algorithm> using namespace clang; +static const enum llvm::raw_ostream::Colors noteColor = + llvm::raw_ostream::BLACK; +static const enum llvm::raw_ostream::Colors fixitColor = + llvm::raw_ostream::GREEN; +static const enum llvm::raw_ostream::Colors caretColor = + llvm::raw_ostream::GREEN; +static const enum llvm::raw_ostream::Colors warningColor = + llvm::raw_ostream::MAGENTA; +static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED; +static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED; +// used for changing only the bold attribute +static const enum llvm::raw_ostream::Colors savedColor = + llvm::raw_ostream::SAVEDCOLOR; + /// \brief Number of spaces to indent when word-wrapping. const unsigned WordWrapIndentation = 6; @@ -396,12 +410,22 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, // Emit what we have computed. OS << SourceLine << '\n'; + + if (UseColors) + OS.changeColor(caretColor, true); OS << CaretLine << '\n'; + if (UseColors) + OS.resetColor(); if (!FixItInsertionLine.empty()) { + if (UseColors) + // Print fixit line in color + OS.changeColor(fixitColor, false); if (PrintRangeInfo) OS << ' '; OS << FixItInsertionLine << '\n'; + if (UseColors) + OS.resetColor(); } } @@ -598,6 +622,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, // Compute the column number. if (ShowLocation) { + if (UseColors) + OS.changeColor(savedColor, true); OS << PLoc.getFilename() << ':' << LineNo << ':'; if (ShowColumn) if (unsigned ColNo = PLoc.getColumn()) @@ -638,6 +664,19 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, OS << ':'; } OS << ' '; + if (UseColors) + OS.resetColor(); + } + } + + if (UseColors) { + // Print diagnostic category in bold and color + switch (Level) { + case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); + case Diagnostic::Note: OS.changeColor(noteColor, true); break; + case Diagnostic::Warning: OS.changeColor(warningColor, true); break; + case Diagnostic::Error: OS.changeColor(errorColor, true); break; + case Diagnostic::Fatal: OS.changeColor(fatalColor, true); break; } } @@ -648,7 +687,10 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, case Diagnostic::Error: OS << "error: "; break; case Diagnostic::Fatal: OS << "fatal error: "; break; } - + + if (UseColors) + OS.resetColor(); + llvm::SmallString<100> OutStr; Info.FormatDiagnostic(OutStr); @@ -659,6 +701,16 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, OutStr += ']'; } + if (UseColors) { + // Print warnings, errors and fatal errors in bold, no color + switch (Level) { + case Diagnostic::Warning: OS.changeColor(savedColor, true); break; + case Diagnostic::Error: OS.changeColor(savedColor, true); break; + case Diagnostic::Fatal: OS.changeColor(savedColor, true); break; + default: break; //don't bold notes + } + } + if (MessageLength) { // We will be word-wrapping the error message, so compute the // column number where we currently are (after printing the @@ -669,6 +721,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, OS.write(OutStr.begin(), OutStr.size()); } OS << '\n'; + if (UseColors) + OS.resetColor(); // If caret diagnostics are enabled and we have location, we want to // emit the caret. However, we only do this if the location moved diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h index c96000a..23a61a0 100644 --- a/lib/Headers/emmintrin.h +++ b/lib/Headers/emmintrin.h @@ -40,7 +40,8 @@ typedef char __v16qi __attribute__((__vector_size__(16))); static inline __m128d __attribute__((__always_inline__, __nodebug__)) _mm_add_sd(__m128d a, __m128d b) { - return __builtin_ia32_addsd(a, b); + a[0] += b[0]; + return a; } static inline __m128d __attribute__((__always_inline__, __nodebug__)) @@ -52,7 +53,8 @@ _mm_add_pd(__m128d a, __m128d b) static inline __m128d __attribute__((__always_inline__, __nodebug__)) _mm_sub_sd(__m128d a, __m128d b) { - return __builtin_ia32_subsd(a, b); + a[0] -= b[0]; + return a; } static inline __m128d __attribute__((__always_inline__, __nodebug__)) @@ -64,7 +66,8 @@ _mm_sub_pd(__m128d a, __m128d b) static inline __m128d __attribute__((__always_inline__, __nodebug__)) _mm_mul_sd(__m128d a, __m128d b) { - return __builtin_ia32_mulsd(a, b); + a[0] *= b[0]; + return a; } static inline __m128d __attribute__((__always_inline__, __nodebug__)) @@ -76,7 +79,8 @@ _mm_mul_pd(__m128d a, __m128d b) static inline __m128d __attribute__((__always_inline__, __nodebug__)) _mm_div_sd(__m128d a, __m128d b) { - return __builtin_ia32_divsd(a, b); + a[0] /= b[0]; + return a; } static inline __m128d __attribute__((__always_inline__, __nodebug__)) @@ -125,25 +129,25 @@ _mm_max_pd(__m128d a, __m128d b) static inline __m128d __attribute__((__always_inline__, __nodebug__)) _mm_and_pd(__m128d a, __m128d b) { - return __builtin_ia32_andpd(a, b); + return (__m128d)((__v4si)a & (__v4si)b); } static inline __m128d __attribute__((__always_inline__, __nodebug__)) _mm_andnot_pd(__m128d a, __m128d b) { - return __builtin_ia32_andnpd(a, b); + return (__m128d)(~(__v4si)a & (__v4si)b); } static inline __m128d __attribute__((__always_inline__, __nodebug__)) _mm_or_pd(__m128d a, __m128d b) { - return __builtin_ia32_orpd(a, b); + return (__m128d)((__v4si)a | (__v4si)b); } static inline __m128d __attribute__((__always_inline__, __nodebug__)) _mm_xor_pd(__m128d a, __m128d b) { - return __builtin_ia32_xorpd(a, b); + return (__m128d)((__v4si)a ^ (__v4si)b); } static inline __m128d __attribute__((__always_inline__, __nodebug__)) @@ -383,19 +387,22 @@ _mm_cvtsd_si32(__m128d a) static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtsd_ss(__m128 a, __m128d b) { - return __builtin_ia32_cvtsd2ss(a, b); + a[0] = b[0]; + return a; } static inline __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi32_sd(__m128d a, int b) { - return __builtin_ia32_cvtsi2sd(a, b); + a[0] = b; + return a; } static inline __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cvtss_sd(__m128d a, __m128 b) { - return __builtin_ia32_cvtss2sd(a, b); + a[0] = b[0]; + return a; } static inline __m128i __attribute__((__always_inline__, __nodebug__)) @@ -407,7 +414,7 @@ _mm_cvttpd_epi32(__m128d a) static inline int __attribute__((__always_inline__, __nodebug__)) _mm_cvttsd_si32(__m128d a) { - return __builtin_ia32_cvttsd2si(a); + return a[0]; } static inline __m64 __attribute__((__always_inline__, __nodebug__)) @@ -669,7 +676,7 @@ _mm_mulhi_epu16(__m128i a, __m128i b) static inline __m128i __attribute__((__always_inline__, __nodebug__)) _mm_mullo_epi16(__m128i a, __m128i b) { - return (__m128i)__builtin_ia32_pmullw128((__v8hi)a, (__v8hi)b); + return (__m128i)((__v8hi)a * (__v8hi)b); } static inline __m64 __attribute__((__always_inline__, __nodebug__)) @@ -747,25 +754,25 @@ _mm_subs_epu16(__m128i a, __m128i b) static inline __m128i __attribute__((__always_inline__, __nodebug__)) _mm_and_si128(__m128i a, __m128i b) { - return __builtin_ia32_pand128(a, b); + return a & b; } static inline __m128i __attribute__((__always_inline__, __nodebug__)) _mm_andnot_si128(__m128i a, __m128i b) { - return __builtin_ia32_pandn128(a, b); + return ~a & b; } static inline __m128i __attribute__((__always_inline__, __nodebug__)) _mm_or_si128(__m128i a, __m128i b) { - return __builtin_ia32_por128(a, b); + return a | b; } static inline __m128i __attribute__((__always_inline__, __nodebug__)) _mm_xor_si128(__m128i a, __m128i b) { - return __builtin_ia32_pxor128(a, b); + return a ^ b; } static inline __m128i __attribute__((__always_inline__, __nodebug__)) @@ -934,7 +941,8 @@ _mm_cmplt_epi32(__m128i a, __m128i b) static inline __m128d __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi64_sd(__m128d a, long long b) { - return __builtin_ia32_cvtsi642sd(a, b); + a[0] = b; + return a; } static inline long long __attribute__((__always_inline__, __nodebug__)) @@ -946,7 +954,7 @@ _mm_cvtsd_si64(__m128d a) static inline long long __attribute__((__always_inline__, __nodebug__)) _mm_cvttsd_si64(__m128d a) { - return __builtin_ia32_cvttsd2si64(a); + return a[0]; } #endif @@ -1181,7 +1189,9 @@ _mm_extract_epi16(__m128i a, int imm) static inline __m128i __attribute__((__always_inline__, __nodebug__)) _mm_insert_epi16(__m128i a, int b, int imm) { - return (__m128i)__builtin_ia32_vec_set_v8hi((__v8hi)a, b, imm); + __v8hi c = (__v8hi)a; + c[imm & 7] = b; + return (__m128i)c; } static inline int __attribute__((__always_inline__, __nodebug__)) @@ -1190,9 +1200,20 @@ _mm_movemask_epi8(__m128i a) return __builtin_ia32_pmovmskb128((__v16qi)a); } -#define _mm_shuffle_epi32(a, imm) ((__m128i)__builtin_ia32_pshufd((__v4si)(a), (imm))) -#define _mm_shufflehi_epi16(a, imm) ((__m128i)__builtin_ia32_pshufhw((__v8hi)(a), (imm))) -#define _mm_shufflelo_epi16(a, imm) ((__m128i)__builtin_ia32_pshuflw((__v8hi)(a), (imm))) +#define _mm_shuffle_epi32(a, imm) \ + ((__m128i)__builtin_shufflevector((__v4si)(a), (__v4si) {0}, \ + (imm) & 0x3, ((imm) & 0xc) >> 2, \ + ((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6)) +#define _mm_shufflelo_epi16(a, imm) \ + ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) {0}, \ + (imm) & 0x3, ((imm) & 0xc) >> 2, \ + ((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6, \ + 4, 5, 6, 7)) +#define _mm_shufflehi_epi16(a, imm) \ + ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) {0}, 0, 1, 2, 3, \ + 4 + ((imm) & 0x3), 4 + ((imm) & 0xc) >> 2, \ + 4 + ((imm) & 0x30) >> 4, \ + 4 + ((imm) & 0xc0) >> 6)) static inline __m128i __attribute__((__always_inline__, __nodebug__)) _mm_unpackhi_epi8(__m128i a, __m128i b) @@ -1257,7 +1278,7 @@ _mm_movpi64_pi64(__m64 a) static inline __m128i __attribute__((__always_inline__, __nodebug__)) _mm_move_epi64(__m128i a) { - return (__m128i){ a[0], 0 }; + return __builtin_shufflevector(a, (__m128i){ 0 }, 0, 2); } static inline __m128d __attribute__((__always_inline__, __nodebug__)) @@ -1278,7 +1299,8 @@ _mm_movemask_pd(__m128d a) return __builtin_ia32_movmskpd(a); } -#define _mm_shuffle_pd(a, b, i) (__builtin_ia32_shufpd((a), (b), (i))) +#define _mm_shuffle_pd(a, b, i) (__builtin_shufflevector((a), (b), (i) & 1, \ + (((i) & 2) >> 1) + 2)) static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_castpd_ps(__m128d in) diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h index 339d212..8ea3c47 100644 --- a/lib/Headers/mmintrin.h +++ b/lib/Headers/mmintrin.h @@ -415,13 +415,13 @@ _mm_set1_pi32(int __i) static inline __m64 __attribute__((__always_inline__, __nodebug__)) _mm_set1_pi16(short __s) { - return (__m64)(__v4hi){ __s }; + return (__m64)(__v4hi){ __s, __s, __s, __s }; } static inline __m64 __attribute__((__always_inline__, __nodebug__)) _mm_set1_pi8(char __b) { - return (__m64)(__v8qi){ __b }; + return (__m64)(__v8qi){ __b, __b, __b, __b, __b, __b, __b, __b }; } static inline __m64 __attribute__((__always_inline__, __nodebug__)) diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h index e9715f1..374a27e 100644 --- a/lib/Headers/tmmintrin.h +++ b/lib/Headers/tmmintrin.h @@ -114,19 +114,19 @@ _mm_hsub_epi16(__m128i a, __m128i b) static inline __m128i __attribute__((__always_inline__, __nodebug__)) _mm_hsub_epi32(__m128i a, __m128i b) { - return (__m128i)__builtin_ia32_psubd128((__v4si)a, (__v4si)b); + return (__m128i)__builtin_ia32_phsubd128((__v4si)a, (__v4si)b); } static inline __m64 __attribute__((__always_inline__, __nodebug__)) _mm_hsub_pi16(__m64 a, __m64 b) { - return (__m64)__builtin_ia32_psubw((__v4hi)a, (__v4hi)b); + return (__m64)__builtin_ia32_phsubw((__v4hi)a, (__v4hi)b); } static inline __m64 __attribute__((__always_inline__, __nodebug__)) _mm_hsub_pi32(__m64 a, __m64 b) { - return (__m64)__builtin_ia32_psubd((__v2si)a, (__v2si)b); + return (__m64)__builtin_ia32_phsubd((__v2si)a, (__v2si)b); } static inline __m128i __attribute__((__always_inline__, __nodebug__)) diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h index c104f63..7291f88 100644 --- a/lib/Headers/xmmintrin.h +++ b/lib/Headers/xmmintrin.h @@ -38,7 +38,8 @@ typedef float __m128 __attribute__((__vector_size__(16))); static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_add_ss(__m128 a, __m128 b) { - return __builtin_ia32_addss(a, b); + a[0] += b[0]; + return a; } static inline __m128 __attribute__((__always_inline__, __nodebug__)) @@ -50,7 +51,8 @@ _mm_add_ps(__m128 a, __m128 b) static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_sub_ss(__m128 a, __m128 b) { - return __builtin_ia32_subss(a, b); + a[0] -= b[0]; + return a; } static inline __m128 __attribute__((__always_inline__, __nodebug__)) @@ -62,7 +64,8 @@ _mm_sub_ps(__m128 a, __m128 b) static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_mul_ss(__m128 a, __m128 b) { - return __builtin_ia32_mulss(a, b); + a[0] *= b[0]; + return a; } static inline __m128 __attribute__((__always_inline__, __nodebug__)) @@ -74,7 +77,8 @@ _mm_mul_ps(__m128 a, __m128 b) static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_div_ss(__m128 a, __m128 b) { - return __builtin_ia32_divss(a, b); + a[0] /= b[0]; + return a; } static inline __m128 __attribute__((__always_inline__, __nodebug__)) @@ -146,25 +150,29 @@ _mm_max_ps(__m128 a, __m128 b) static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_and_ps(__m128 a, __m128 b) { - return __builtin_ia32_andps(a, b); + typedef int __v4si __attribute__((__vector_size__(16))); + return (__m128)((__v4si)a & (__v4si)b); } static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_andnot_ps(__m128 a, __m128 b) { - return __builtin_ia32_andnps(a, b); + typedef int __v4si __attribute__((__vector_size__(16))); + return (__m128)(~(__v4si)a & (__v4si)b); } static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_or_ps(__m128 a, __m128 b) { - return __builtin_ia32_orps(a, b); + typedef int __v4si __attribute__((__vector_size__(16))); + return (__m128)((__v4si)a | (__v4si)b); } static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_xor_ps(__m128 a, __m128 b) { - return __builtin_ia32_xorps(a, b); + typedef int __v4si __attribute__((__vector_size__(16))); + return (__m128)((__v4si)a ^ ~(__v4si)b); } static inline __m128 __attribute__((__always_inline__, __nodebug__)) @@ -389,12 +397,16 @@ _mm_cvtss_si32(__m128 a) return __builtin_ia32_cvtss2si(a); } +#ifdef __x86_64__ + static inline long long __attribute__((__always_inline__, __nodebug__)) _mm_cvtss_si64(__m128 a) { return __builtin_ia32_cvtss2si64(a); } +#endif + static inline __m64 __attribute__((__always_inline__, __nodebug__)) _mm_cvtps_pi32(__m128 a) { @@ -404,13 +416,13 @@ _mm_cvtps_pi32(__m128 a) static inline int __attribute__((__always_inline__, __nodebug__)) _mm_cvttss_si32(__m128 a) { - return __builtin_ia32_cvttss2si(a); + return a[0]; } static inline long long __attribute__((__always_inline__, __nodebug__)) _mm_cvttss_si64(__m128 a) { - return __builtin_ia32_cvttss2si64(a); + return a[0]; } static inline __m64 __attribute__((__always_inline__, __nodebug__)) @@ -422,7 +434,8 @@ _mm_cvttps_pi32(__m128 a) static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi32_ss(__m128 a, int b) { - return __builtin_ia32_cvtsi2ss(a, b); + a[0] = b; + return a; } #ifdef __x86_64__ @@ -430,7 +443,8 @@ _mm_cvtsi32_ss(__m128 a, int b) static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi64_ss(__m128 a, long long b) { - return __builtin_ia32_cvtsi642ss(a, b); + a[0] = b; + return a; } #endif @@ -456,6 +470,13 @@ _mm_loadh_pi(__m128 a, __m64 const *p) static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_loadl_pi(__m128 a, __m64 const *p) { +#if 0 + // FIXME: This should work, but gives really crappy code at the moment + __m128 b; + b[0] = *(float*)p; + b[1] = *((float*)p+1); + return __builtin_shufflevector(a, b, 0, 1, 4, 5); +#endif return __builtin_ia32_loadlps(a, (__v2si *)p); } @@ -604,26 +625,17 @@ _mm_sfence(void) static inline int __attribute__((__always_inline__, __nodebug__)) _mm_extract_pi16(__m64 a, int n) { - /* FIXME: - * This should force n to be an immediate. - * This does not use the PEXTRW instruction. From looking at the LLVM source, the - instruction doesn't seem to be hooked up. - * The code could probably be made better :) - */ __v4hi b = (__v4hi)a; - return b[(n == 0) ? 0 : (n == 1 ? 1 : (n == 2 ? 2 : 3))]; + return (unsigned short)b[n & 3]; } -/* FIXME: Implement this. We could add a __builtin_insertelement function that's similar to - the already existing __builtin_shufflevector. -*/ -/* static inline __m64 __attribute__((__always_inline__, __nodebug__)) _mm_insert_pi16(__m64 a, int d, int n) { - return (__m64){ 0LL }; + __v4hi b = (__v4hi)a; + b[n & 3] = d; + return (__m64)b; } -*/ static inline __m64 __attribute__((__always_inline__, __nodebug__)) _mm_max_pi16(__m64 a, __m64 b) @@ -661,7 +673,10 @@ _mm_mulhi_pu16(__m64 a, __m64 b) return (__m64)__builtin_ia32_pmulhuw((__v4hi)a, (__v4hi)b); } -#define _mm_shuffle_pi16(a, n) ((__m64)__builtin_ia32_pshufw((__v4hi)a, n)) +#define _mm_shuffle_pi16(a, n) \ + ((__m64)__builtin_shufflevector((__v4hi)(a), (__v4hi) {0}, \ + (n) & 0x3, ((n) & 0xc) >> 2, \ + ((n) & 0x30) >> 4, ((n) & 0xc0) >> 6)) static inline void __attribute__((__always_inline__, __nodebug__)) _mm_maskmove_si64(__m64 d, __m64 n, char *p) @@ -699,7 +714,10 @@ _mm_setcsr(unsigned int i) __builtin_ia32_ldmxcsr(i); } -#define _mm_shuffle_ps(a, b, mask) (__builtin_ia32_shufps(a, b, mask)) +#define _mm_shuffle_ps(a, b, mask) \ + (__builtin_shufflevector(a, b, (mask) & 0x3, ((mask) & 0xc) >> 2, \ + (((mask) & 0x30) >> 4) + 4, \ + (((mask) & 0xc0) >> 6) + 4)) static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_unpackhi_ps(__m128 a, __m128 b) diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 0324c0b..4d10974 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -691,7 +691,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, // character constants are not sign extended in the this implementation: // '\xFF\xFF' = 65536 and '\x0\xFF' = 255, which matches GCC. if (!IsWide && NumCharsSoFar == 1 && (Value & 128) && - PP.getTargetInfo().isCharSigned()) + PP.getLangOptions().CharIsSigned) Value = (signed char)Value; } diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index 709e316..c98acc4 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -232,7 +232,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, // Set the value. Val = Literal.getValue(); // Set the signedness. - Val.setIsUnsigned(!TI.isCharSigned()); + Val.setIsUnsigned(!PP.getLangOptions().CharIsSigned); if (Result.Val.getBitWidth() > Val.getBitWidth()) { Result.Val = Val.extend(Result.Val.getBitWidth()); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 3014f95..cb7fe58 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -891,6 +891,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, // Install the declarator into interfaceDecl. DeclPtrTy Field = Actions.ActOnIvar(CurScope, DS.getSourceRange().getBegin(), + interfaceDecl, FD.D, FD.BitfieldSize, visibility); AllIvarDecls.push_back(Field); } diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 94695e4..58c729a 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -100,6 +100,12 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { return; } + PP.Lex(Tok); + if (Tok.isNot(tok::eom)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack"; + return; + } + SourceLocation RParenLoc = Tok.getLocation(); Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc, LParenLoc, RParenLoc); @@ -172,7 +178,14 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) { PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc); return; } - + + PP.Lex(Tok); + if (Tok.isNot(tok::eom)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << + "unused"; + return; + } + // Verify that we have a location for the right parenthesis. assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'"); assert(!Ex.empty() && "Valid '#pragma unused' must have arguments"); @@ -180,3 +193,45 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) { // Perform the action to handle the pragma. Actions.ActOnPragmaUnused(&Ex[0], Ex.size(), UnusedLoc, LParenLoc, RParenLoc); } + +// #pragma weak identifier +// #pragma weak identifier '=' identifier +void PragmaWeakHandler::HandlePragma(Preprocessor &PP, Token &WeakTok) { + // FIXME: Should we be expanding macros here? My guess is no. + SourceLocation WeakLoc = WeakTok.getLocation(); + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak"; + return; + } + + IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0; + SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc; + + PP.Lex(Tok); + if (Tok.is(tok::equal)) { + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "weak"; + return; + } + AliasName = Tok.getIdentifierInfo(); + AliasNameLoc = Tok.getLocation(); + PP.Lex(Tok); + } + + if (Tok.isNot(tok::eom)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak"; + return; + } + + if (AliasName) { + Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc, + AliasNameLoc); + } else { + Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc); + } +} diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index 31b2a5f..39c86ee 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -39,6 +39,15 @@ public: virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); }; +class PragmaWeakHandler : public PragmaHandler { + Action &Actions; +public: + PragmaWeakHandler(const IdentifierInfo *N, Action &A) + : PragmaHandler(N), Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); +}; + } // end namespace clang #endif diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 758b662..f041d7d 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -550,6 +550,8 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { if (ParseParenExprOrCondition(CondExp)) return StmtError(); + FullExprArg FullCondExp(Actions.FullExpr(CondExp)); + // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. @@ -631,7 +633,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement() { if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); - return Actions.ActOnIfStmt(IfLoc, Actions.FullExpr(CondExp), move(ThenStmt), + return Actions.ActOnIfStmt(IfLoc, FullCondExp, move(ThenStmt), ElseLoc, move(ElseStmt)); } @@ -752,6 +754,8 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() { if (ParseParenExprOrCondition(Cond)) return StmtError(); + FullExprArg FullCond(Actions.FullExpr(Cond)); + // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. @@ -776,7 +780,7 @@ Parser::OwningStmtResult Parser::ParseWhileStatement() { if (Cond.isInvalid() || Body.isInvalid()) return StmtError(); - return Actions.ActOnWhileStmt(WhileLoc, Actions.FullExpr(Cond), move(Body)); + return Actions.ActOnWhileStmt(WhileLoc, FullCond, move(Body)); } /// ParseDoStatement diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 1c2e8a6..a2a66f9 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -39,6 +39,10 @@ Parser::Parser(Preprocessor &pp, Action &actions) PragmaUnusedHandler(&PP.getIdentifierTable().get("unused"), actions, *this)); PP.AddPragmaHandler(0, UnusedHandler.get()); + + WeakHandler.reset(new + PragmaWeakHandler(&PP.getIdentifierTable().get("weak"), actions)); + PP.AddPragmaHandler(0, WeakHandler.get()); } /// If a crash happens while the parser is active, print out a line indicating @@ -288,6 +292,8 @@ Parser::~Parser() { PackHandler.reset(); PP.RemovePragmaHandler(0, UnusedHandler.get()); UnusedHandler.reset(); + PP.RemovePragmaHandler(0, WeakHandler.get()); + WeakHandler.reset(); } /// Initialize - Warm up the parser. diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 321dac1..85c67df 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -23,6 +23,7 @@ add_clang_library(clangSema SemaOverload.cpp SemaStmt.cpp SemaTemplate.cpp + SemaTemplateDeduction.cpp SemaTemplateInstantiate.cpp SemaTemplateInstantiateDecl.cpp SemaTemplateInstantiateExpr.cpp diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index c428d29..d3bfef6 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -20,6 +20,7 @@ #include "SemaOverload.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/Parse/Action.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallVector.h" @@ -471,6 +472,7 @@ public: Declarator *D = 0); virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, + DeclPtrTy IntfDecl, Declarator &D, ExprTy *BitfieldWidth, tok::ObjCKeywordKind visibility); @@ -1045,7 +1047,7 @@ public: LookupResult LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, bool RedeclarationOnly = false, - bool AllowBuiltinCreation = true, + bool AllowBuiltinCreation = false, SourceLocation Loc = SourceLocation()); LookupResult LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, LookupNameKind NameKind, @@ -1054,7 +1056,7 @@ public: DeclarationName Name, LookupNameKind NameKind, bool RedeclarationOnly = false, - bool AllowBuiltinCreation = true, + bool AllowBuiltinCreation = false, SourceLocation Loc = SourceLocation()); ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II); @@ -1629,6 +1631,12 @@ public: TypeTy *Ty, SourceLocation RParen); + /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is + /// non-empty, will create a new CXXExprWithTemporaries expression. + /// Otherwise, just returs the passed in expression. + Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, + bool DestroyTemps = true); + virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr); bool RequireCompleteDeclContext(const CXXScopeSpec &SS); @@ -1971,7 +1979,7 @@ public: const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc, - llvm::SmallVectorImpl<TemplateArgument> &Converted); + TemplateArgumentListBuilder &Converted); bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg, SourceLocation ArgLoc); @@ -1980,7 +1988,7 @@ public: bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member); bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, - llvm::SmallVectorImpl<TemplateArgument> *Converted = 0); + TemplateArgumentListBuilder *Converted = 0); bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg); bool TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, @@ -2019,16 +2027,9 @@ public: const IdentifierInfo &II, SourceRange Range); - bool DeduceTemplateArguments(QualType Param, QualType Arg, - llvm::SmallVectorImpl<TemplateArgument> &Deduced); - bool DeduceTemplateArguments(const TemplateArgument &Param, - const TemplateArgument &Arg, - llvm::SmallVectorImpl<TemplateArgument> &Deduced); - bool DeduceTemplateArguments(const TemplateArgumentList &ParamList, - const TemplateArgumentList &ArgList, - llvm::SmallVectorImpl<TemplateArgument> &Deduced); - bool DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, - const TemplateArgumentList &TemplateArgs); + TemplateArgumentList * + DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs); //===--------------------------------------------------------------------===// // C++ Template Instantiation @@ -2235,7 +2236,7 @@ public: QualType InstantiateType(QualType T, const TemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); - + OwningExprResult InstantiateExpr(Expr *E, const TemplateArgumentList &TemplateArgs); @@ -2456,7 +2457,19 @@ public: SourceLocation PragmaLoc, SourceLocation LParenLoc, SourceLocation RParenLoc); - + + /// ActOnPragmaWeakID - Called on well formed #pragma weak ident. + virtual void ActOnPragmaWeakID(IdentifierInfo* WeakName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc); + + /// ActOnPragmaWeakAlias - Called on well formed #pragma weak ident = ident. + virtual void ActOnPragmaWeakAlias(IdentifierInfo* WeakName, + IdentifierInfo* AliasName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc, + SourceLocation AliasNameLoc); + /// getPragmaPackAlignment() - Return the current alignment as specified by /// the current #pragma pack directive, or 0 if none is currently active. unsigned getPragmaPackAlignment() const; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 959154c..c67af29 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -575,10 +575,11 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) { // If we have a redefinition of a typedef in C, emit a warning. This warning // is normally mapped to an error, but can be controlled with - // -Wtypedef-redefinition. If either the original was in a system header, - // don't emit this for compatibility with GCC. + // -Wtypedef-redefinition. If either the original or the redefinition is + // in a system header, don't emit this for compatibility with GCC. if (PP.getDiagnostics().getSuppressSystemWarnings() && - Context.getSourceManager().isInSystemHeader(Old->getLocation())) + (Context.getSourceManager().isInSystemHeader(Old->getLocation()) || + Context.getSourceManager().isInSystemHeader(New->getLocation()))) return; Diag(New->getLocation(), diag::warn_redefinition_of_typedef) @@ -3913,6 +3914,7 @@ TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { /// in order to create an IvarDecl object for it. Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, SourceLocation DeclStart, + DeclPtrTy IntfDecl, Declarator &D, ExprTy *BitfieldWidth, tok::ObjCKeywordKind Visibility) { @@ -3951,14 +3953,28 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, ObjCIvarDecl::AccessControl ac = Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility) : ObjCIvarDecl::None; - + // Must set ivar's DeclContext to its enclosing interface. + Decl *EnclosingDecl = IntfDecl.getAs<Decl>(); + DeclContext *EnclosingContext; + if (ObjCImplementationDecl *IMPDecl = + dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) { + // Case of ivar declared in an implementation. Context is that of its class. + ObjCInterfaceDecl* IDecl = IMPDecl->getClassInterface(); + assert(IDecl && "No class- ActOnIvar"); + EnclosingContext = cast_or_null<DeclContext>(IDecl); + } + else + EnclosingContext = dyn_cast<DeclContext>(EnclosingDecl); + assert(EnclosingContext && "null DeclContext for ivar - ActOnIvar"); + // Construct the decl. - ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, CurContext, Loc, II, T,ac, + ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, + EnclosingContext, Loc, II, T,ac, (Expr *)BitfieldWidth); if (II) { NamedDecl *PrevDecl = LookupName(S, II, LookupMemberName, true); - if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S) + if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S) && !isa<TagDecl>(PrevDecl)) { Diag(Loc, diag::err_duplicate_member) << II; Diag(PrevDecl->getLocation(), diag::note_previous_declaration); @@ -4099,7 +4115,11 @@ void Sema::ActOnFields(Scope* S, if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl)) { ID->setIVarList(ClsFields, RecFields.size(), Context); ID->setLocEnd(RBrac); - + // Add ivar's to class's DeclContext. + for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { + ClsFields[i]->setLexicalDeclContext(ID); + ID->addDecl(Context, ClsFields[i]); + } // Must enforce the rule that ivars in the base classes may not be // duplicates. if (ID->getSuperClass()) { @@ -4120,12 +4140,10 @@ void Sema::ActOnFields(Scope* S, } else if (ObjCImplementationDecl *IMPDecl = dyn_cast<ObjCImplementationDecl>(EnclosingDecl)) { assert(IMPDecl && "ActOnFields - missing ObjCImplementationDecl"); - for (unsigned I = 0, N = RecFields.size(); I != N; ++I) { - // FIXME: Set the DeclContext correctly when we build the - // declarations. + for (unsigned I = 0, N = RecFields.size(); I != N; ++I) + // Ivar declared in @implementation never belongs to the implementation. + // Only it is in implementation's lexical context. ClsFields[I]->setLexicalDeclContext(IMPDecl); - IMPDecl->addDecl(Context, ClsFields[I]); - } CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); } } @@ -4413,3 +4431,34 @@ Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, CurContext->addDecl(Context, New); return DeclPtrTy::make(New); } + +void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, + SourceLocation PragmaLoc, + SourceLocation NameLoc) { + Decl *PrevDecl = LookupName(TUScope, Name, LookupOrdinaryName); + + // FIXME: This implementation is an ugly hack! + if (PrevDecl) { + PrevDecl->addAttr(::new (Context) WeakAttr()); + return; + } + Diag(PragmaLoc, diag::err_unsupported_pragma_weak); + return; +} + +void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name, + IdentifierInfo* AliasName, + SourceLocation PragmaLoc, + SourceLocation NameLoc, + SourceLocation AliasNameLoc) { + Decl *PrevDecl = LookupName(TUScope, Name, LookupOrdinaryName); + + // FIXME: This implementation is an ugly hack! + if (PrevDecl) { + PrevDecl->addAttr(::new (Context) AliasAttr(AliasName->getName())); + PrevDecl->addAttr(::new (Context) WeakAttr()); + return; + } + Diag(PragmaLoc, diag::err_unsupported_pragma_weak); + return; +} diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index f13179f..b59ac87 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1357,7 +1357,7 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { if (!Constructor->isInvalidDecl() && ((Constructor->getNumParams() == 1) || (Constructor->getNumParams() > 1 && - Constructor->getParamDecl(1)->getDefaultArg() != 0))) { + Constructor->getParamDecl(1)->hasDefaultArg()))) { QualType ParamType = Constructor->getParamDecl(0)->getType(); QualType ClassTy = Context.getTagDeclType(ClassDecl); if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 8f58034..2500a8f 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -2113,27 +2113,6 @@ bool Sema::CheckObjCDeclScope(Decl *D) { return true; } -/// Collect the instance variables declared in an Objective-C object. Used in -/// the creation of structures from objects using the @defs directive. -/// FIXME: This should be consolidated with CollectObjCIvars as it is also -/// part of the AST generation logic of @defs. -static void CollectIvars(ObjCInterfaceDecl *Class, RecordDecl *Record, - ASTContext& Ctx, - llvm::SmallVectorImpl<Sema::DeclPtrTy> &ivars) { - if (Class->getSuperClass()) - CollectIvars(Class->getSuperClass(), Record, Ctx, ivars); - - // For each ivar, create a fresh ObjCAtDefsFieldDecl. - for (ObjCInterfaceDecl::ivar_iterator I = Class->ivar_begin(), - E = Class->ivar_end(); I != E; ++I) { - ObjCIvarDecl* ID = *I; - Decl *FD = ObjCAtDefsFieldDecl::Create(Ctx, Record, ID->getLocation(), - ID->getIdentifier(), ID->getType(), - ID->getBitWidth()); - ivars.push_back(Sema::DeclPtrTy::make(FD)); - } -} - /// Called whenever @defs(ClassName) is encountered in the source. Inserts the /// instance variables of ClassName into Decls. void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, @@ -2151,7 +2130,17 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, } // Collect the instance variables - CollectIvars(Class, dyn_cast<RecordDecl>(TagD.getAs<Decl>()), Context, Decls); + llvm::SmallVector<FieldDecl*, 32> RecFields; + Context.CollectObjCIvars(Class, RecFields); + // For each ivar, create a fresh ObjCAtDefsFieldDecl. + for (unsigned i = 0; i < RecFields.size(); i++) { + FieldDecl* ID = RecFields[i]; + RecordDecl *Record = dyn_cast<RecordDecl>(TagD.getAs<Decl>()); + Decl *FD = ObjCAtDefsFieldDecl::Create(Context, Record, ID->getLocation(), + ID->getIdentifier(), ID->getType(), + ID->getBitWidth()); + Decls.push_back(Sema::DeclPtrTy::make(FD)); + } // Introduce all of these fields into the appropriate scope. for (llvm::SmallVectorImpl<DeclPtrTy>::iterator D = Decls.begin(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 65018da..ed4ac55 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1588,16 +1588,26 @@ Expr *Sema::RemoveOutermostTemporaryBinding(Expr *E) { return E; } +Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, + bool DestroyTemps) { + assert(SubExpr && "sub expression can't be null!"); + + if (ExprTemporaries.empty()) + return SubExpr; + + Expr *E = CXXExprWithTemporaries::Create(Context, SubExpr, + &ExprTemporaries[0], + ExprTemporaries.size(), + DestroyTemps); + ExprTemporaries.clear(); + + return E; +} + Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { Expr *FullExpr = Arg.takeAs<Expr>(); - - if (FullExpr && !ExprTemporaries.empty()) { - // Create a cleanup expr. - FullExpr = CXXExprWithTemporaries::Create(Context, FullExpr, - &ExprTemporaries[0], - ExprTemporaries.size()); - ExprTemporaries.clear(); - } + if (FullExpr) + FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr); return Owned(FullExpr); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 782a0d8..f9176ca 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -750,6 +750,10 @@ static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs, Canonical.reserve(NumTemplateArgs); for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) { switch (TemplateArgs[Idx].getKind()) { + case TemplateArgument::Null: + assert(false && "Should never see a NULL template argument here"); + break; + case TemplateArgument::Expression: // FIXME: Build canonical expression (!) Canonical.push_back(TemplateArgs[Idx]); @@ -765,11 +769,13 @@ static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs, Canonical.push_back(TemplateArgument(SourceLocation(), *TemplateArgs[Idx].getAsIntegral(), TemplateArgs[Idx].getIntegralType())); + break; case TemplateArgument::Type: { QualType CanonType = Context.getCanonicalType(TemplateArgs[Idx].getAsType()); Canonical.push_back(TemplateArgument(SourceLocation(), CanonType)); + break; } } } @@ -805,7 +811,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Check that the template argument list is well-formed for this // template. - llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs; + TemplateArgumentListBuilder ConvertedTemplateArgs(Context); if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, TemplateArgs, NumTemplateArgs, RAngleLoc, ConvertedTemplateArgs)) @@ -829,15 +835,16 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // template<typename T, typename U = T> struct A; TemplateName CanonName = Context.getCanonicalTemplateName(Name); CanonType = Context.getTemplateSpecializationType(CanonName, - &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size()); + ConvertedTemplateArgs.getFlatArgumentList(), + ConvertedTemplateArgs.flatSize()); } else if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(Template)) { // Find the class template specialization declaration that // corresponds to these arguments. llvm::FoldingSetNodeID ID; - ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size()); + ClassTemplateSpecializationDecl::Profile(ID, + ConvertedTemplateArgs.getFlatArgumentList(), + ConvertedTemplateArgs.flatSize()); void *InsertPos = 0; ClassTemplateSpecializationDecl *Decl = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); @@ -846,12 +853,10 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // specialization. Create the canonical declaration and add it to // the set of specializations. Decl = ClassTemplateSpecializationDecl::Create(Context, - ClassTemplate->getDeclContext(), - TemplateLoc, - ClassTemplate, - &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size(), - 0); + ClassTemplate->getDeclContext(), + TemplateLoc, + ClassTemplate, + ConvertedTemplateArgs, 0); ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos); Decl->setLexicalDeclContext(CurContext); } @@ -949,7 +954,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + TemplateArgumentListBuilder &Converted) { TemplateParameterList *Params = Template->getTemplateParameters(); unsigned NumParams = Params->size(); unsigned NumArgs = NumTemplateArgs; @@ -998,13 +1003,13 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // on the previously-computed template arguments. if (ArgType->isDependentType()) { InstantiatingTemplate Inst(*this, TemplateLoc, - Template, &Converted[0], - Converted.size(), + Template, Converted.getFlatArgumentList(), + Converted.flatSize(), SourceRange(TemplateLoc, RAngleLoc)); - TemplateArgumentList TemplateArgs(Context, &Converted[0], - Converted.size(), - /*CopyArgs=*/false); + TemplateArgumentList TemplateArgs(Context, Converted, + /*CopyArgs=*/false, + /*FlattenArgs=*/false); ArgType = InstantiateType(ArgType, TemplateArgs, TTP->getDefaultArgumentLoc(), TTP->getDeclName()); @@ -1069,13 +1074,13 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (NTTPType->isDependentType()) { // Instantiate the type of the non-type template parameter. InstantiatingTemplate Inst(*this, TemplateLoc, - Template, &Converted[0], - Converted.size(), + Template, Converted.getFlatArgumentList(), + Converted.flatSize(), SourceRange(TemplateLoc, RAngleLoc)); - TemplateArgumentList TemplateArgs(Context, &Converted[0], - Converted.size(), - /*CopyArgs=*/false); + TemplateArgumentList TemplateArgs(Context, Converted, + /*CopyArgs=*/false, + /*FlattenArgs=*/false); NTTPType = InstantiateType(NTTPType, TemplateArgs, NTTP->getLocation(), NTTP->getDeclName()); @@ -1092,6 +1097,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, } switch (Arg.getKind()) { + case TemplateArgument::Null: + assert(false && "Should never see a NULL template argument here"); + break; + case TemplateArgument::Expression: { Expr *E = Arg.getAsExpr(); if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted)) @@ -1131,6 +1140,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, = cast<TemplateTemplateParmDecl>(*Param); switch (Arg.getKind()) { + case TemplateArgument::Null: + assert(false && "Should never see a NULL template argument here"); + break; + case TemplateArgument::Expression: { Expr *ArgExpr = Arg.getAsExpr(); if (ArgExpr && isa<DeclRefExpr>(ArgExpr) && @@ -1379,7 +1392,7 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { /// of this argument will be added to the end of the Converted vector. bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, - llvm::SmallVectorImpl<TemplateArgument> *Converted) { + TemplateArgumentListBuilder *Converted) { SourceLocation StartLoc = Arg->getSourceRange().getBegin(); // If either the parameter has a dependent type or the argument is @@ -2051,7 +2064,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // Check that the template argument list is well-formed for this // template. - llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs; + TemplateArgumentListBuilder ConvertedTemplateArgs(Context); if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, &TemplateArgs[0], TemplateArgs.size(), RAngleLoc, ConvertedTemplateArgs)) @@ -2066,11 +2079,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, llvm::FoldingSetNodeID ID; if (isPartialSpecialization) // FIXME: Template parameter list matters, too - ClassTemplatePartialSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size()); + ClassTemplatePartialSpecializationDecl::Profile(ID, + ConvertedTemplateArgs.getFlatArgumentList(), + ConvertedTemplateArgs.flatSize()); else - ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size()); + ClassTemplateSpecializationDecl::Profile(ID, + ConvertedTemplateArgs.getFlatArgumentList(), + ConvertedTemplateArgs.flatSize()); void *InsertPos = 0; ClassTemplateSpecializationDecl *PrevDecl = 0; @@ -2111,12 +2126,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, ClassTemplatePartialSpecializationDecl *Partial = ClassTemplatePartialSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), - TemplateNameLoc, - TemplateParams, - ClassTemplate, - &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size(), - PrevPartial); + TemplateNameLoc, + TemplateParams, + ClassTemplate, + ConvertedTemplateArgs, + PrevPartial); if (PrevPartial) { ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial); @@ -2132,9 +2146,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, = ClassTemplateSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), TemplateNameLoc, - ClassTemplate, - &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size(), + ClassTemplate, + ConvertedTemplateArgs, PrevDecl); if (PrevDecl) { @@ -2255,9 +2268,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, // Check that the template argument list is well-formed for this // template. - llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs; + TemplateArgumentListBuilder ConvertedTemplateArgs(Context); if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, - &TemplateArgs[0], TemplateArgs.size(), + TemplateArgs.data(), TemplateArgs.size(), RAngleLoc, ConvertedTemplateArgs)) return true; @@ -2268,8 +2281,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, // Find the class template specialization declaration that // corresponds to these arguments. llvm::FoldingSetNodeID ID; - ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size()); + ClassTemplateSpecializationDecl::Profile(ID, + ConvertedTemplateArgs.getFlatArgumentList(), + ConvertedTemplateArgs.flatSize()); void *InsertPos = 0; ClassTemplateSpecializationDecl *PrevDecl = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); @@ -2312,9 +2326,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, ClassTemplate->getDeclContext(), TemplateNameLoc, ClassTemplate, - &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size(), - 0); + ConvertedTemplateArgs, 0); Specialization->setLexicalDeclContext(CurContext); CurContext->addDecl(Context, Specialization); return DeclPtrTy::make(Specialization); @@ -2340,9 +2352,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, ClassTemplate->getDeclContext(), TemplateNameLoc, ClassTemplate, - &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size(), - 0); + ConvertedTemplateArgs, 0); ClassTemplate->getSpecializations().InsertNode(Specialization, InsertPos); @@ -2357,7 +2367,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, // arguments in the specialization. QualType WrittenTy = Context.getTemplateSpecializationType(Name, - &TemplateArgs[0], + TemplateArgs.data(), TemplateArgs.size(), Context.getTypeDeclType(Specialization)); Specialization->setTypeAsWritten(WrittenTy); @@ -2563,89 +2573,3 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, << Name; return QualType(); } - -// FIXME: Move to SemaTemplateDeduction.cpp -bool -Sema::DeduceTemplateArguments(QualType Param, QualType Arg, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { - // We only want to look at the canonical types, since typedefs and - // sugar are not part of template argument deduction. - Param = Context.getCanonicalType(Param); - Arg = Context.getCanonicalType(Arg); - - // If the parameter type is not dependent, just compare the types - // directly. - if (!Param->isDependentType()) - return Param == Arg; - - // FIXME: Use a visitor or switch to handle all of the kinds of - // types that the parameter may be. - if (const TemplateTypeParmType *TemplateTypeParm - = Param->getAsTemplateTypeParmType()) { - (void)TemplateTypeParm; // FIXME: use this - // The argument type can not be less qualified than the parameter - // type. - if (Param.isMoreQualifiedThan(Arg)) - return false; - - unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers(); - QualType DeducedType = Arg.getQualifiedType(Quals); - // FIXME: actually save the deduced type, and check that this - // deduction is consistent. - return true; - } - - if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) - return false; - - if (const PointerType *PointerParam = Param->getAsPointerType()) { - const PointerType *PointerArg = Arg->getAsPointerType(); - if (!PointerArg) - return false; - - return DeduceTemplateArguments(PointerParam->getPointeeType(), - PointerArg->getPointeeType(), - Deduced); - } - - // FIXME: Many more cases to go (to go). - return false; -} - -bool -Sema::DeduceTemplateArguments(const TemplateArgument &Param, - const TemplateArgument &Arg, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { - assert(Param.getKind() == Arg.getKind() && - "Template argument kind mismatch during deduction"); - switch (Param.getKind()) { - case TemplateArgument::Type: - return DeduceTemplateArguments(Param.getAsType(), Arg.getAsType(), - Deduced); - - default: - return false; - } -} - -bool -Sema::DeduceTemplateArguments(const TemplateArgumentList &ParamList, - const TemplateArgumentList &ArgList, - llvm::SmallVectorImpl<TemplateArgument> &Deduced) { - assert(ParamList.size() == ArgList.size()); - for (unsigned I = 0, N = ParamList.size(); I != N; ++I) { - if (!DeduceTemplateArguments(ParamList[I], ArgList[I], Deduced)) - return false; - } - return true; -} - - -bool -Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, - const TemplateArgumentList &TemplateArgs) { - llvm::SmallVector<TemplateArgument, 4> Deduced; - Deduced.resize(Partial->getTemplateParameters()->size()); - return DeduceTemplateArguments(Partial->getTemplateArgs(), TemplateArgs, - Deduced); -} diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp new file mode 100644 index 0000000..812b319 --- /dev/null +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -0,0 +1,395 @@ +//===------- SemaTemplateDeduction.cpp - Template Argument Deduction ------===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file implements C++ template argument deduction. +// +//===----------------------------------------------------------------------===/ + +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Parse/DeclSpec.h" +#include "llvm/Support/Compiler.h" +using namespace clang; + +/// \brief If the given expression is of a form that permits the deduction +/// of a non-type template parameter, return the declaration of that +/// non-type template parameter. +static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { + if (ImplicitCastExpr *IC = dyn_cast<ImplicitCastExpr>(E)) + E = IC->getSubExpr(); + + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + return dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()); + + return 0; +} + +/// \brief Deduce the value of the given non-type template parameter +/// from the given constant. +/// +/// \returns true if deduction succeeded, false otherwise. +static bool DeduceNonTypeTemplateArgument(ASTContext &Context, + NonTypeTemplateParmDecl *NTTP, + llvm::APInt Value, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + assert(NTTP->getDepth() == 0 && + "Cannot deduce non-type template argument with depth > 0"); + + if (Deduced[NTTP->getIndex()].isNull()) { + Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(), + llvm::APSInt(Value), + NTTP->getType()); + return true; + } + + if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral) + return false; + + // If the template argument was previously deduced to a negative value, + // then our deduction fails. + const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral(); + assert(PrevValuePtr && "Not an integral template argument?"); + if (PrevValuePtr->isSigned() && PrevValuePtr->isNegative()) + return false; + + llvm::APInt PrevValue = *PrevValuePtr; + if (Value.getBitWidth() > PrevValue.getBitWidth()) + PrevValue.zext(Value.getBitWidth()); + else if (Value.getBitWidth() < PrevValue.getBitWidth()) + Value.zext(PrevValue.getBitWidth()); + return Value == PrevValue; +} + +/// \brief Deduce the value of the given non-type template parameter +/// from the given type- or value-dependent expression. +/// +/// \returns true if deduction succeeded, false otherwise. + +static bool DeduceNonTypeTemplateArgument(ASTContext &Context, + NonTypeTemplateParmDecl *NTTP, + Expr *Value, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + assert(NTTP->getDepth() == 0 && + "Cannot deduce non-type template argument with depth > 0"); + assert((Value->isTypeDependent() || Value->isValueDependent()) && + "Expression template argument must be type- or value-dependent."); + + if (Deduced[NTTP->getIndex()].isNull()) { + // FIXME: Clone the Value? + Deduced[NTTP->getIndex()] = TemplateArgument(Value); + return true; + } + + if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral) { + // Okay, we deduced a constant in one case and a dependent expression + // in another case. FIXME: Later, we will check that instantiating the + // dependent expression gives us the constant value. + return true; + } + + // FIXME: Compare the expressions for equality! + return true; +} + +static bool DeduceTemplateArguments(ASTContext &Context, QualType Param, + QualType Arg, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + // We only want to look at the canonical types, since typedefs and + // sugar are not part of template argument deduction. + Param = Context.getCanonicalType(Param); + Arg = Context.getCanonicalType(Arg); + + // If the parameter type is not dependent, just compare the types + // directly. + if (!Param->isDependentType()) + return Param == Arg; + + // C++ [temp.deduct.type]p9: + // + // A template type argument T, a template template argument TT or a + // template non-type argument i can be deduced if P and A have one of + // the following forms: + // + // T + // cv-list T + if (const TemplateTypeParmType *TemplateTypeParm + = Param->getAsTemplateTypeParmType()) { + // The argument type can not be less qualified than the parameter + // type. + if (Param.isMoreQualifiedThan(Arg)) + return false; + + assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0"); + + unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers(); + QualType DeducedType = Arg.getQualifiedType(Quals); + unsigned Index = TemplateTypeParm->getIndex(); + + if (Deduced[Index].isNull()) + Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType); + else { + // C++ [temp.deduct.type]p2: + // [...] If type deduction cannot be done for any P/A pair, or if for + // any pair the deduction leads to more than one possible set of + // deduced values, or if different pairs yield different deduced + // values, or if any template argument remains neither deduced nor + // explicitly specified, template argument deduction fails. + if (Deduced[Index].getAsType() != DeducedType) + return false; + } + return true; + } + + if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) + return false; + + switch (Param->getTypeClass()) { + // No deduction possible for these types + case Type::Builtin: + return false; + + + // T * + case Type::Pointer: { + const PointerType *PointerArg = Arg->getAsPointerType(); + if (!PointerArg) + return false; + + return DeduceTemplateArguments(Context, + cast<PointerType>(Param)->getPointeeType(), + PointerArg->getPointeeType(), + Deduced); + } + + // T & + case Type::LValueReference: { + const LValueReferenceType *ReferenceArg = Arg->getAsLValueReferenceType(); + if (!ReferenceArg) + return false; + + return DeduceTemplateArguments(Context, + cast<LValueReferenceType>(Param)->getPointeeType(), + ReferenceArg->getPointeeType(), + Deduced); + } + + // T && [C++0x] + case Type::RValueReference: { + const RValueReferenceType *ReferenceArg = Arg->getAsRValueReferenceType(); + if (!ReferenceArg) + return false; + + return DeduceTemplateArguments(Context, + cast<RValueReferenceType>(Param)->getPointeeType(), + ReferenceArg->getPointeeType(), + Deduced); + } + + // T [] (implied, but not stated explicitly) + case Type::IncompleteArray: { + const IncompleteArrayType *IncompleteArrayArg = + Context.getAsIncompleteArrayType(Arg); + if (!IncompleteArrayArg) + return false; + + return DeduceTemplateArguments(Context, + Context.getAsIncompleteArrayType(Param)->getElementType(), + IncompleteArrayArg->getElementType(), + Deduced); + } + + // T [integer-constant] + case Type::ConstantArray: { + const ConstantArrayType *ConstantArrayArg = + Context.getAsConstantArrayType(Arg); + if (!ConstantArrayArg) + return false; + + const ConstantArrayType *ConstantArrayParm = + Context.getAsConstantArrayType(Param); + if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize()) + return false; + + return DeduceTemplateArguments(Context, + ConstantArrayParm->getElementType(), + ConstantArrayArg->getElementType(), + Deduced); + } + + // type [i] + case Type::DependentSizedArray: { + const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg); + if (!ArrayArg) + return false; + + // Check the element type of the arrays + const DependentSizedArrayType *DependentArrayParm + = cast<DependentSizedArrayType>(Param); + if (!DeduceTemplateArguments(Context, + DependentArrayParm->getElementType(), + ArrayArg->getElementType(), + Deduced)) + return false; + + // Determine the array bound is something we can deduce. + NonTypeTemplateParmDecl *NTTP + = getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr()); + if (!NTTP) + return true; + + // We can perform template argument deduction for the given non-type + // template parameter. + assert(NTTP->getDepth() == 0 && + "Cannot deduce non-type template argument at depth > 0"); + if (const ConstantArrayType *ConstantArrayArg + = dyn_cast<ConstantArrayType>(ArrayArg)) + return DeduceNonTypeTemplateArgument(Context, NTTP, + ConstantArrayArg->getSize(), + Deduced); + if (const DependentSizedArrayType *DependentArrayArg + = dyn_cast<DependentSizedArrayType>(ArrayArg)) + return DeduceNonTypeTemplateArgument(Context, NTTP, + DependentArrayArg->getSizeExpr(), + Deduced); + + // Incomplete type does not match a dependently-sized array type + return false; + } + + default: + break; + } + + // FIXME: Many more cases to go (to go). + return false; +} + +static bool +DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param, + const TemplateArgument &Arg, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + switch (Param.getKind()) { + case TemplateArgument::Null: + assert(false && "Null template argument in parameter list"); + break; + + case TemplateArgument::Type: + assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch"); + return DeduceTemplateArguments(Context, Param.getAsType(), + Arg.getAsType(), Deduced); + + case TemplateArgument::Declaration: + // FIXME: Implement this check + assert(false && "Unimplemented template argument deduction case"); + return false; + + case TemplateArgument::Integral: + if (Arg.getKind() == TemplateArgument::Integral) { + // FIXME: Zero extension + sign checking here? + return *Param.getAsIntegral() == *Arg.getAsIntegral(); + } + if (Arg.getKind() == TemplateArgument::Expression) + return false; + + assert(false && "Type/value mismatch"); + return false; + + case TemplateArgument::Expression: { + if (NonTypeTemplateParmDecl *NTTP + = getDeducedParameterFromExpr(Param.getAsExpr())) { + if (Arg.getKind() == TemplateArgument::Integral) + // FIXME: Sign problems here + return DeduceNonTypeTemplateArgument(Context, NTTP, + *Arg.getAsIntegral(), Deduced); + if (Arg.getKind() == TemplateArgument::Expression) + return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(), + Deduced); + + assert(false && "Type/value mismatch"); + return false; + } + + // Can't deduce anything, but that's okay. + return true; + } + } + + return true; +} + +static bool +DeduceTemplateArguments(ASTContext &Context, + const TemplateArgumentList &ParamList, + const TemplateArgumentList &ArgList, + llvm::SmallVectorImpl<TemplateArgument> &Deduced) { + assert(ParamList.size() == ArgList.size()); + for (unsigned I = 0, N = ParamList.size(); I != N; ++I) { + if (!DeduceTemplateArguments(Context, ParamList[I], ArgList[I], Deduced)) + return false; + } + return true; +} + + +TemplateArgumentList * +Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs) { + // Deduce the template arguments for the partial specialization + llvm::SmallVector<TemplateArgument, 4> Deduced; + Deduced.resize(Partial->getTemplateParameters()->size()); + if (! ::DeduceTemplateArguments(Context, Partial->getTemplateArgs(), + TemplateArgs, Deduced)) + return 0; + + // FIXME: Substitute the deduced template arguments into the template + // arguments of the class template partial specialization; the resulting + // template arguments should match TemplateArgs exactly. + + for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { + TemplateArgument &Arg = Deduced[I]; + + // FIXME: If this template argument was not deduced, but the corresponding + // template parameter has a default argument, instantiate the default + // argument. + if (Arg.isNull()) // FIXME: Result->Destroy(Context); + return 0; + + if (Arg.getKind() == TemplateArgument::Integral) { + // FIXME: Instantiate the type, but we need some context! + const NonTypeTemplateParmDecl *Parm + = cast<NonTypeTemplateParmDecl>(Partial->getTemplateParameters() + ->getParam(I)); + // QualType T = InstantiateType(Parm->getType(), *Result, + // Parm->getLocation(), Parm->getDeclName()); + // if (T.isNull()) // FIXME: Result->Destroy(Context); + // return 0; + QualType T = Parm->getType(); + + // FIXME: Make sure we didn't overflow our data type! + llvm::APSInt &Value = *Arg.getAsIntegral(); + unsigned AllowedBits = Context.getTypeSize(T); + if (Value.getBitWidth() != AllowedBits) + Value.extOrTrunc(AllowedBits); + Value.setIsSigned(T->isSignedIntegerType()); + Arg.setIntegralType(T); + } + } + + // FIXME: This is terrible. DeduceTemplateArguments should use a + // TemplateArgumentListBuilder directly. + TemplateArgumentListBuilder Builder(Context); + for (unsigned I = 0, N = Deduced.size(); I != N; ++I) + Builder.push_back(Deduced[I]); + + return new (Context) TemplateArgumentList(Context, Builder, /*CopyArgs=*/true, + /*FlattenArgs=*/true); +} diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index d3d771b..562749e 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -503,6 +503,10 @@ InstantiateTemplateSpecializationType( for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end(); Arg != ArgEnd; ++Arg) { switch (Arg->getKind()) { + case TemplateArgument::Null: + assert(false && "Should never have a NULL template argument"); + break; + case TemplateArgument::Type: { QualType T = SemaRef.InstantiateType(Arg->getAsType(), TemplateArgs, @@ -829,21 +833,23 @@ Sema::InstantiateClassTemplateSpecialization( // Determine whether any class template partial specializations // match the given template arguments. - llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> Matched; + typedef std::pair<ClassTemplatePartialSpecializationDecl *, + TemplateArgumentList *> MatchResult; + llvm::SmallVector<MatchResult, 4> Matched; for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator Partial = Template->getPartialSpecializations().begin(), PartialEnd = Template->getPartialSpecializations().end(); Partial != PartialEnd; ++Partial) { - if (DeduceTemplateArguments(&*Partial, ClassTemplateSpec->getTemplateArgs())) - Matched.push_back(&*Partial); + if (TemplateArgumentList *Deduced + = DeduceTemplateArguments(&*Partial, + ClassTemplateSpec->getTemplateArgs())) + Matched.push_back(std::make_pair(&*Partial, Deduced)); } if (Matched.size() == 1) { - Pattern = Matched[0]; - // FIXME: set TemplateArgs to the template arguments of the - // partial specialization, instantiated with the deduced template - // arguments. + Pattern = Matched[0].first; + TemplateArgs = Matched[0].second; } else if (Matched.size() > 1) { // FIXME: Implement partial ordering of class template partial // specializations. @@ -856,9 +862,17 @@ Sema::InstantiateClassTemplateSpecialization( ExplicitInstantiation? TSK_ExplicitInstantiation : TSK_ImplicitInstantiation); - return InstantiateClass(ClassTemplateSpec->getLocation(), - ClassTemplateSpec, Pattern, *TemplateArgs, - ExplicitInstantiation); + bool Result = InstantiateClass(ClassTemplateSpec->getLocation(), + ClassTemplateSpec, Pattern, *TemplateArgs, + ExplicitInstantiation); + + for (unsigned I = 0, N = Matched.size(); I != N; ++I) { + // FIXME: Implement TemplateArgumentList::Destroy! + // if (Matched[I].first != Pattern) + // Matched[I].second->Destroy(Context); + } + + return Result; } /// \brief Instantiate the definitions of all of the member of the diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index a6b9703..5ba42f2 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -119,12 +119,13 @@ TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) { T->isWideCharType(), T, E->getSourceRange().getBegin())); - else if (T->isBooleanType()) + if (T->isBooleanType()) return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr( Arg.getAsIntegral()->getBoolValue(), T, E->getSourceRange().getBegin())); + assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T)); return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( *Arg.getAsIntegral(), T, diff --git a/lib/Sema/SemaTemplateInstantiateStmt.cpp b/lib/Sema/SemaTemplateInstantiateStmt.cpp index 1f69479..fd349df 100644 --- a/lib/Sema/SemaTemplateInstantiateStmt.cpp +++ b/lib/Sema/SemaTemplateInstantiateStmt.cpp @@ -194,6 +194,8 @@ Sema::OwningStmtResult TemplateStmtInstantiator::VisitIfStmt(IfStmt *S) { if (Cond.isInvalid()) return SemaRef.StmtError(); + Sema::FullExprArg FullCond(FullExpr(Cond)); + // Instantiate the "then" branch. OwningStmtResult Then = SemaRef.InstantiateStmt(S->getThen(), TemplateArgs); if (Then.isInvalid()) @@ -204,7 +206,7 @@ Sema::OwningStmtResult TemplateStmtInstantiator::VisitIfStmt(IfStmt *S) { if (Else.isInvalid()) return SemaRef.StmtError(); - return SemaRef.ActOnIfStmt(S->getIfLoc(), FullExpr(Cond), move(Then), + return SemaRef.ActOnIfStmt(S->getIfLoc(), FullCond, move(Then), S->getElseLoc(), move(Else)); } @@ -236,12 +238,14 @@ Sema::OwningStmtResult TemplateStmtInstantiator::VisitWhileStmt(WhileStmt *S) { if (Cond.isInvalid()) return SemaRef.StmtError(); + Sema::FullExprArg FullCond(FullExpr(Cond)); + // Instantiate the body OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs); if (Body.isInvalid()) return SemaRef.StmtError(); - return SemaRef.ActOnWhileStmt(S->getWhileLoc(), FullExpr(Cond), move(Body)); + return SemaRef.ActOnWhileStmt(S->getWhileLoc(), FullCond, move(Body)); } Sema::OwningStmtResult TemplateStmtInstantiator::VisitDoStmt(DoStmt *S) { diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c index ea8b7f5..34840c7 100644 --- a/test/Analysis/ptr-arith.c +++ b/test/Analysis/ptr-arith.c @@ -18,7 +18,7 @@ void f2() { // This test case checks if we get the right rvalue type of a TypedViewRegion. // The ElementRegion's type depends on the array region's rvalue type. If it was // a pointer type, we would get a loc::SymbolVal for '*p'. -char* memchr(); +void* memchr(); static int domain_port (const char *domain_b, const char *domain_e, const char **domain_e_ptr) diff --git a/test/Analysis/retain-release-gc-only.m b/test/Analysis/retain-release-gc-only.m index cc4a40d..ec33a57 100644 --- a/test/Analysis/retain-release-gc-only.m +++ b/test/Analysis/retain-release-gc-only.m @@ -5,6 +5,8 @@ // Header stuff. //===----------------------------------------------------------------------===// +typedef struct objc_class *Class; + typedef unsigned int __darwin_natural_t; typedef struct {} div_t; typedef unsigned long UInt32; @@ -56,6 +58,7 @@ typedef struct _NSZone NSZone; @end @protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end @interface NSObject <NSObject> {} +- (Class)class; + (id)alloc; + (id)allocWithZone:(NSZone *)zone; @end typedef float CGFloat; @@ -173,6 +176,28 @@ void f5b() { @end //===----------------------------------------------------------------------===// +// <rdar://problem/6948053> False positive: object substitution during -init* +// methods warns about returning +0 when using -fobjc-gc-only +//===----------------------------------------------------------------------===// + +@interface MyClassRdar6948053 : NSObject +- (id) init; ++ (id) shared; +@end + +@implementation MyClassRdar6948053 ++(id) shared { + return (id) 0; +} +- (id) init +{ + Class myClass = [self class]; + [self release]; + return [[myClass shared] retain]; // no-warning +} +@end + +//===----------------------------------------------------------------------===// // Tests of ownership attributes. //===----------------------------------------------------------------------===// @@ -189,3 +214,27 @@ void test_attr_1b(TestOwnershipAttr *X) { NSString *str = [X returnsAnOwnedCFString]; // expected-warning{{leak}} } +@interface MyClassTestCFAttr : NSObject {} +- (NSDate*) returnsCFRetained __attribute__((cf_returns_retained)); +- (NSDate*) alsoReturnsRetained; +- (NSDate*) returnsNSRetained __attribute__((ns_returns_retained)); +@end + +__attribute__((cf_returns_retained)) +CFDateRef returnsRetainedCFDate() { + return CFDateCreate(0, CFAbsoluteTimeGetCurrent()); +} + +@implementation MyClassTestCFAttr +- (NSDate*) returnsCFRetained { + return (NSDate*) returnsRetainedCFDate(); // No leak. +} + +- (NSDate*) alsoReturnsRetained { + return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}} +} + +- (NSDate*) returnsNSRetained { + return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}} +} +@end
\ No newline at end of file diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m index 3ff007e..c7c5e24 100644 --- a/test/Analysis/retain-release.m +++ b/test/Analysis/retain-release.m @@ -704,5 +704,31 @@ void test_attr_1(TestOwnershipAttr *X) { void test_attr_1b(TestOwnershipAttr *X) { NSString *str = [X returnsAnOwnedCFString]; // expected-warning{{leak}} } -//<<SLICER + +@interface MyClassTestCFAttr : NSObject {} +- (NSDate*) returnsCFRetained __attribute__((cf_returns_retained)); +- (NSDate*) alsoReturnsRetained; +- (NSDate*) returnsNSRetained __attribute__((ns_returns_retained)); +@end + +__attribute__((cf_returns_retained)) +CFDateRef returnsRetainedCFDate() { + return CFDateCreate(0, CFAbsoluteTimeGetCurrent()); +} + +@implementation MyClassTestCFAttr +- (NSDate*) returnsCFRetained { + return (NSDate*) returnsRetainedCFDate(); // No leak. +} + +- (NSDate*) alsoReturnsRetained { + return (NSDate*) returnsRetainedCFDate(); // expected-warning{{leak}} +} + +- (NSDate*) returnsNSRetained { + return (NSDate*) returnsRetainedCFDate(); // no-warning +} +@end + + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..ba5a025 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,53 @@ +find_file(CLANG_TEST_RUNNER TestRunner.sh PATHS ${CMAKE_CURRENT_SOURCE_DIR} + DOC "Clang's regression testing script") +mark_as_advanced(CLANG_TEST_RUNNER) + +set(CLANG_TEST_DIRECTORIES + "Analysis" + "CodeGen" + "CodeGenCXX" + "CodeGenObjC" + "Coverage" + "Driver" + "FixIt" + "Frontend" + "Lexer" + "Misc" + "PCH" + "Parser" + "Preprocessor" + "Rewriter" + "Sema" + "SemaCXX" + "SemaObjC" + "SemaObjCXX" + "SemaTemplate") + +include(FindPythonInterp) +if(PYTHONINTERP_FOUND) + get_target_property(LLVM_TOOLS_PATH clang RUNTIME_OUTPUT_DIRECTORY) + set(TESTING_EXTRA_PATHS + "${LLVM_TOOLS_PATH}/${CMAKE_CFG_INTDIR}:${LLVM_SOURCE_DIR}/test/Scripts") + set(all_testdirs) + foreach(testdir ${CLANG_TEST_DIRECTORIES}) + add_custom_target(clang-test-${testdir} + ${PYTHON_EXECUTABLE} + ${LLVM_SOURCE_DIR}/tools/clang/utils/test/MultiTestRunner.py + -s + "--path=${TESTING_EXTRA_PATHS}" + ${CMAKE_CURRENT_SOURCE_DIR}/${testdir}/ + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Running Clang regression tests in ${testdir}") + + list(APPEND all_testdirs ${CMAKE_CURRENT_SOURCE_DIR}/${testdir}/) + endforeach() + + add_custom_target(clang-test + ${PYTHON_EXECUTABLE} + ${LLVM_SOURCE_DIR}/tools/clang/utils/test/MultiTestRunner.py + "--path=${TESTING_EXTRA_PATHS}" + ${all_testdirs} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS clang clang-cc + COMMENT "Running Clang regression tests") +endif() diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c index d45d512..a5de4f4 100644 --- a/test/CodeGen/attributes.c +++ b/test/CodeGen/attributes.c @@ -14,7 +14,7 @@ // RUN: grep '@t13 =.*section "SECT"' %t && // RUN: grep '@t14.x =.*section "SECT"' %t // RUN: grep 'declare extern_weak i32 @t15()' %t && -// RUN: grep '@t16 = extern_weak global i32' %t +// RUN: grep '@t16 = extern_weak global i32' %t && void t1() __attribute__((noreturn)); void t1() {} @@ -56,4 +56,14 @@ int t17() { return t15() + t16; } +// RUN: grep '@t18 = global i[0-9]* 1, align .*' %t && +extern int t18 __attribute__((weak_import)); +int t18 = 1; +// RUN: grep 'define i[0-9]* @t19() nounwind {' %t && +extern int t19(void) __attribute__((weak_import)); +int t19(void) { + return 10; +} + +// RUN: true diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c index 6f7ec82..0b68afd 100644 --- a/test/CodeGen/x86_64-arguments.c +++ b/test/CodeGen/x86_64-arguments.c @@ -82,4 +82,10 @@ void f16(float a, float b, float c, float d, float e, float f, float g, float h, void f17(float a, float b, float c, float d, float e, float f, float g, float h, long double X) {} +// Check for valid coercion. +// RUN: grep '.1 = bitcast i64. .tmp to .struct.f18_s0.' %t && +// RUN: grep '.2 = load .struct.f18_s0. .1, align 1' %t && +// RUN: grep 'store .struct.f18_s0 .2, .struct.f18_s0. .f18_arg1' %t && +void f18(int a, struct f18_s0 { int f0; } f18_arg1) {} + // RUN: true diff --git a/test/CodeGenObjC/blocks-3.m b/test/CodeGenObjC/blocks-3.m new file mode 100644 index 0000000..96e436b --- /dev/null +++ b/test/CodeGenObjC/blocks-3.m @@ -0,0 +1,15 @@ +// RUN: clang-cc -triple x86_64-apple-darwin9 -emit-llvm -fblocks -o %t %s && +// RUN: grep 'object_assign' %t | count 11 && +// RUN: grep 'object_dispose' %t | count 29 + +int main() { + typedef id aid __attribute__((aligned(1))); + __block aid a1; + __block id a2 __attribute__((aligned(2))); + __block id a3 __attribute__((aligned(4))); + __block id a4 __attribute__((aligned(8))); + __block id a5, a6, a7; + __block void (^b)(); + ^{ a1=a2=a3=a4=a5=a6=a7=0; b = 0; }(); + return 0; +} diff --git a/test/Driver/flags.c b/test/Driver/flags.c index 53f3995..7c448fa 100644 --- a/test/Driver/flags.c +++ b/test/Driver/flags.c @@ -1,9 +1,9 @@ // RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S -msoft-float %s 2> %t.log && -// RUN: grep '"--soft-float"' %t.log && +// RUN: grep '"--no-implicit-float"' %t.log && // RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S -msoft-float -mno-soft-float %s 2> %t.log && -// RUN: grep '"--soft-float"' %t.log | count 0 && +// RUN: grep '"--no-implicit-float"' %t.log | count 0 && // RUN: clang -ccc-host-triple i386-apple-darwin9 -### -S -mno-soft-float %s -msoft-float 2> %t.log && -// RUN: grep '"--soft-float"' %t.log +// RUN: grep '"--no-implicit-float"' %t.log diff --git a/test/Driver/redzone.c b/test/Driver/redzone.c new file mode 100644 index 0000000..8709e71 --- /dev/null +++ b/test/Driver/redzone.c @@ -0,0 +1,6 @@ +// RUN: clang -mno-red-zone %s -S -emit-llvm -o %t.log && +// RUN: grep 'noredzone' %t.log +// RUN: clang -mred-zone %s -S -emit-llvm -o %t.log && +// RUN: grep -v 'noredzone' %t.log + +int foo() { return 42; } diff --git a/test/Parser/pragma-weak.c b/test/Parser/pragma-weak.c new file mode 100644 index 0000000..355a954 --- /dev/null +++ b/test/Parser/pragma-weak.c @@ -0,0 +1,17 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// Note that this puts the expected lines before the directives to work around +// limitations in the -verify mode. + +int x; +/* expected-warning {{expected identifier in '#pragma weak'}}*/ #pragma weak +#pragma weak x + +extern int z; +/* expected-warning {{expected identifier in '#pragma weak'}}*/ #pragma weak z = = +/* expected-warning {{expected identifier in '#pragma weak'}}*/ #pragma weak z = +#pragma weak z = y + +extern int a; +/* expected-warning {{extra tokens at end of '#pragma weak'}}*/ #pragma weak a b +/* expected-warning {{extra tokens at end of '#pragma weak'}}*/ #pragma weak a = x c diff --git a/test/Sema/const-eval.c b/test/Sema/const-eval.c index 79f96b9..971986b 100644 --- a/test/Sema/const-eval.c +++ b/test/Sema/const-eval.c @@ -65,3 +65,4 @@ static const struct a V1 = (struct a){ 1, 2}; EVAL_EXPR(30, (int)(_Complex float)((1<<30)-1) == (1<<30) ? 1 : -1) EVAL_EXPR(31, (int*)0 == (int*)0 ? 1 : -1) EVAL_EXPR(32, (int*)0 != (int*)0 ? -1 : 1) +EVAL_EXPR(33, (void*)0 - (void*)0 == 0 ? 1 : -1) diff --git a/test/SemaObjCXX/references.mm b/test/SemaObjCXX/references.mm new file mode 100644 index 0000000..6a28ea9 --- /dev/null +++ b/test/SemaObjCXX/references.mm @@ -0,0 +1,27 @@ +// RUN: clang-cc -verify -emit-llvm -o %t %s +// XFAIL + +// Test reference binding. + +typedef struct { + int f0; + int f1; +} T; + +@interface A +@property (assign) T p0; +@property (assign) T& p1; +@end + +int f0(const T& t) { + return t.f0; +} + +int f1(A *a) { + return f0(a.p0); +} + +int f2(A *a) { + return f0(a.p1); +} + diff --git a/test/SemaTemplate/ackermann.cpp b/test/SemaTemplate/ackermann.cpp new file mode 100644 index 0000000..48fbbbb --- /dev/null +++ b/test/SemaTemplate/ackermann.cpp @@ -0,0 +1,37 @@ +// RUN: clang-cc -fsyntax-only -ftemplate-depth=1000 -verify %s + +// template<unsigned M, unsigned N> +// struct Ackermann { +// enum { +// value = M ? (N ? Ackermann<M-1, Ackermann<M-1, N-1> >::value +// : Ackermann<M-1, 1>::value) +// : N + 1 +// }; +// }; + +template<unsigned M, unsigned N> +struct Ackermann { + enum { + value = Ackermann<M-1, Ackermann<M, N-1>::value >::value + }; +}; + +template<unsigned M> struct Ackermann<M, 0> { + enum { + value = Ackermann<M-1, 1>::value + }; +}; + +template<unsigned N> struct Ackermann<0, N> { + enum { + value = N + 1 + }; +}; + +template<> struct Ackermann<0, 0> { + enum { + value = 1 + }; +}; + +int g0[Ackermann<3, 8>::value == 2045 ? 1 : -1]; diff --git a/test/SemaTemplate/default-arguments.cpp b/test/SemaTemplate/default-arguments.cpp index 572227c..5b6ab7d 100644 --- a/test/SemaTemplate/default-arguments.cpp +++ b/test/SemaTemplate/default-arguments.cpp @@ -10,3 +10,6 @@ X<> *x3; // expected-error{{too few template arguments for class template 'X'}} template<typename U = float, int M> struct X; X<> *x4; + +template<typename T = int> struct Z { }; +template struct Z<>; diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp index df652b5..8cb46cf 100644 --- a/test/SemaTemplate/temp_class_spec.cpp +++ b/test/SemaTemplate/temp_class_spec.cpp @@ -18,3 +18,87 @@ int array0[is_pointer<int>::value? -1 : 1]; int array1[is_pointer<int*>::value? 1 : -1]; int array2[is_pointer<const int*>::value? 1 : -1]; // expected-error{{partial ordering}} \ // expected-error{{negative}} + +template<typename T> +struct is_lvalue_reference { + static const bool value = false; +}; + +template<typename T> +struct is_lvalue_reference<T&> { + static const bool value = true; +}; + +int lvalue_ref0[is_lvalue_reference<int>::value? -1 : 1]; +int lvalue_ref1[is_lvalue_reference<const int&>::value? 1 : -1]; + +template<typename T, typename U> +struct is_same { + static const bool value = false; +}; + +template<typename T> +struct is_same<T, T> { + static const bool value = true; +}; + +typedef int INT; +typedef INT* int_ptr; + +int is_same0[is_same<int, int>::value? 1 : -1]; +int is_same1[is_same<int, INT>::value? 1 : -1]; +int is_same2[is_same<const int, int>::value? -1 : 1]; +int is_same3[is_same<int_ptr, int>::value? -1 : 1]; + +template<typename T> +struct remove_reference { + typedef T type; +}; + +template<typename T> +struct remove_reference<T&> { + typedef T type; +}; + +int remove_ref0[is_same<remove_reference<int>::type, int>::value? 1 : -1]; +int remove_ref1[is_same<remove_reference<int&>::type, int>::value? 1 : -1]; + +template<typename T> +struct is_incomplete_array { + static const bool value = false; +}; + +template<typename T> +struct is_incomplete_array<T[]> { + static const bool value = true; +}; + +int incomplete_array0[is_incomplete_array<int>::value ? -1 : 1]; +int incomplete_array1[is_incomplete_array<int[1]>::value ? -1 : 1]; +int incomplete_array2[is_incomplete_array<bool[]>::value ? 1 : -1]; +int incomplete_array3[is_incomplete_array<int[]>::value ? 1 : -1]; + +template<typename T> +struct is_array_with_4_elements { + static const bool value = false; +}; + +template<typename T> +struct is_array_with_4_elements<T[4]> { + static const bool value = true; +}; + +int array_with_4_elements0[is_array_with_4_elements<int[]>::value ? -1 : 1]; +int array_with_4_elements1[is_array_with_4_elements<int[1]>::value ? -1 : 1]; +int array_with_4_elements2[is_array_with_4_elements<int[4]>::value ? 1 : -1]; +int array_with_4_elements3[is_array_with_4_elements<int[4][2]>::value ? 1 : -1]; + +template<typename T> +struct get_array_size; + +template<typename T, unsigned N> +struct get_array_size<T[N]> { + static const unsigned value = N; +}; + +int array_size0[get_array_size<int[12]>::value == 12? 1 : -1]; diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp index 0e0a072..f38c6bd 100644 --- a/tools/clang-cc/clang-cc.cpp +++ b/tools/clang-cc/clang-cc.cpp @@ -328,6 +328,11 @@ MessageLength("fmessage-length", "within N columns or fewer, when possible."), llvm::cl::value_desc("N")); +static llvm::cl::opt<bool> +NoColorDiagnostic("fno-color-diagnostics", + llvm::cl::desc("Don't use colors when showing diagnostics " + "(automatically turned off if output is not a " + "terminal).")); //===----------------------------------------------------------------------===// // C++ Visualization. //===----------------------------------------------------------------------===// @@ -649,6 +654,9 @@ NeXTRuntime("fnext-runtime", llvm::cl::desc("Generate output compatible with the NeXT " "runtime")); +static llvm::cl::opt<bool> +CharIsSigned("fsigned-char", + llvm::cl::desc("Force char to be a signed/unsigned type")); static llvm::cl::opt<bool> @@ -807,6 +815,8 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK, Options.Exceptions = Exceptions; if (EnableBlocks.getPosition()) Options.Blocks = EnableBlocks; + if (CharIsSigned.getPosition()) + Options.CharIsSigned = CharIsSigned; if (!AllowBuiltins) Options.NoBuiltin = 1; @@ -1390,6 +1400,17 @@ TargetCPU("mcpu", static llvm::cl::list<std::string> TargetFeatures("target-feature", llvm::cl::desc("Target specific attributes")); + +static llvm::cl::opt<bool> +DisableRedZone("disable-red-zone", + llvm::cl::desc("Do not emit code that uses the red zone."), + llvm::cl::init(false)); + +static llvm::cl::opt<bool> +NoImplicitFloat("no-implicit-float", + llvm::cl::desc("Don't generate implicit floating point instructions (x86-only)"), + llvm::cl::init(false)); + /// ComputeTargetFeatures - Recompute the target feature list to only /// be the list of things that are enabled, based on the target cpu /// and feature list. @@ -1466,6 +1487,9 @@ static void InitializeCompileOptions(CompileOptions &Opts, // Handle -ftime-report. Opts.TimePasses = TimeReport; + + Opts.DisableRedZone = DisableRedZone; + Opts.NoImplicitFloat = NoImplicitFloat; } //===----------------------------------------------------------------------===// @@ -2150,6 +2174,10 @@ int main(int argc, char **argv) { if (MessageLength.getNumOccurrences() == 0) MessageLength.setValue(llvm::sys::Process::StandardErrColumns()); + if (!NoColorDiagnostic) { + NoColorDiagnostic.setValue(!llvm::sys::Process::StandardErrHasColors()); + } + DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), !NoShowColumn, !NoCaretDiagnostics, @@ -2157,7 +2185,8 @@ int main(int argc, char **argv) { PrintSourceRangeInfo, PrintDiagnosticOption, !NoDiagnosticsFixIt, - MessageLength)); + MessageLength, + !NoColorDiagnostic)); } else { DiagClient.reset(CreateHTMLDiagnosticClient(HTMLDiag)); } diff --git a/utils/test/MultiTestRunner.py b/utils/test/MultiTestRunner.py index 57650f9..5dde1bd 100755 --- a/utils/test/MultiTestRunner.py +++ b/utils/test/MultiTestRunner.py @@ -249,6 +249,10 @@ def main(): parser.add_option("", "--debug-do-not-test", dest="debugDoNotTest", help="DEBUG: Skip running actual test script", action="store_true", default=False) + parser.add_option("", "--path", dest="path", + help="Additional paths to add to testing environment", + action="store", type=str, default=None) + (opts, args) = parser.parse_args() if not args: @@ -269,7 +273,10 @@ def main(): random.shuffle(tests) if opts.maxTests is not None: tests = tests[:opts.maxTests] - + if opts.path is not None: + os.environ["PATH"] = opts.path + ":" + os.environ["PATH"]; + print "Current PATH is: ", os.environ["PATH"] + extra = '' if len(tests) != len(allTests): extra = ' of %d'%(len(allTests),) diff --git a/www/menu.html.incl b/www/menu.html.incl index ab3bf1d..44f6861 100644 --- a/www/menu.html.incl +++ b/www/menu.html.incl @@ -8,11 +8,16 @@ <a href="/index.html">About</a> <a href="/features.html">Features</a> <a href="/comparison.html">Comparisons</a> + <a href="/docs/UsersManual.html">Users Manual</a> + <a href="/docs/LanguageExtensions.html">Language Extensions</a> + <a href="/cxx_status.html">C++ Status</a> + </div> + + <div class="submenu"> + <label>Clang Development</label> <a href="/get_started.html">Get Started</a> <a href="/get_involved.html">Get Involved</a> <a href="/OpenProjects.html">Open Projects</a> - <a href="/cxx_status.html">C++ Status</a> - <a href="/docs/LanguageExtensions.html">Language Extensions</a> <a href="/docs/InternalsManual.html">Clang Internals</a> <a href="/hacking.html">Hacking on Clang</a> <a href="/performance.html">Performance</a> |