From 265c92560db8af7e64dc328cb612076086a62bd1 Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 6 Jun 2009 08:21:31 +0000 Subject: Import clang, at r72995. --- CMakeLists.txt | 1 + clang.xcodeproj/project.pbxproj | 16 +- docs/PCHInternals.html | 112 +- docs/UsersManual.html | 33 +- include/clang/AST/ASTContext.h | 7 +- include/clang/AST/Builtins.def | 32 +- include/clang/AST/Decl.h | 16 +- include/clang/AST/DeclObjC.h | 1 + include/clang/AST/DeclTemplate.h | 67 +- include/clang/AST/ExprCXX.h | 9 +- include/clang/Basic/DiagnosticFrontendKinds.td | 3 + include/clang/Basic/DiagnosticParseKinds.td | 2 + include/clang/Basic/DiagnosticSemaKinds.td | 2 + include/clang/Basic/LangOptions.h | 3 + include/clang/Basic/TargetInfo.h | 6 - include/clang/Driver/Options.def | 8 + include/clang/Frontend/CompileOptions.h | 4 + include/clang/Frontend/TextDiagnosticPrinter.h | 7 +- include/clang/Parse/Action.h | 21 +- include/clang/Parse/Parser.h | 1 + lib/AST/ASTContext.cpp | 74 +- lib/AST/Decl.cpp | 2 +- lib/AST/DeclCXX.cpp | 4 +- lib/AST/DeclObjC.cpp | 22 +- lib/AST/DeclPrinter.cpp | 46 +- lib/AST/DeclTemplate.cpp | 46 +- lib/AST/ExprCXX.cpp | 11 +- lib/AST/ExprConstant.cpp | 3 +- lib/AST/Type.cpp | 8 + lib/Analysis/CFRefCount.cpp | 25 +- lib/Basic/TargetInfo.cpp | 1 - lib/Basic/Targets.cpp | 17 +- lib/CodeGen/ABIInfo.h | 33 +- lib/CodeGen/CGBlocks.cpp | 39 +- lib/CodeGen/CGBlocks.h | 12 +- lib/CodeGen/CGCXXTemp.cpp | 79 +- lib/CodeGen/CGCall.cpp | 1389 +----------------------- lib/CodeGen/CGDecl.cpp | 19 +- lib/CodeGen/CGExprAgg.cpp | 4 + lib/CodeGen/CGExprScalar.cpp | 12 +- lib/CodeGen/CGObjCGNU.cpp | 8 +- lib/CodeGen/CGObjCMac.cpp | 46 +- lib/CodeGen/CMakeLists.txt | 2 + lib/CodeGen/CodeGenFunction.h | 19 + lib/CodeGen/CodeGenModule.cpp | 7 +- lib/CodeGen/TargetABIInfo.cpp | 1379 +++++++++++++++++++++++ lib/Driver/Tools.cpp | 15 +- lib/Frontend/InitPreprocessor.cpp | 11 +- lib/Frontend/PCHReader.cpp | 1 + lib/Frontend/PCHWriter.cpp | 2 + lib/Frontend/PrintParserCallbacks.cpp | 1 + lib/Frontend/TextDiagnosticPrinter.cpp | 56 +- lib/Headers/emmintrin.h | 72 +- lib/Headers/mmintrin.h | 4 +- lib/Headers/tmmintrin.h | 6 +- lib/Headers/xmmintrin.h | 72 +- lib/Lex/LiteralSupport.cpp | 2 +- lib/Lex/PPExpressions.cpp | 2 +- lib/Parse/ParseObjc.cpp | 1 + lib/Parse/ParsePragma.cpp | 57 +- lib/Parse/ParsePragma.h | 9 + lib/Parse/ParseStmt.cpp | 8 +- lib/Parse/Parser.cpp | 6 + lib/Sema/CMakeLists.txt | 1 + lib/Sema/Sema.h | 45 +- lib/Sema/SemaDecl.cpp | 73 +- lib/Sema/SemaDeclCXX.cpp | 2 +- lib/Sema/SemaDeclObjC.cpp | 33 +- lib/Sema/SemaExprCXX.cpp | 26 +- lib/Sema/SemaTemplate.cpp | 192 +--- lib/Sema/SemaTemplateDeduction.cpp | 395 +++++++ lib/Sema/SemaTemplateInstantiate.cpp | 34 +- lib/Sema/SemaTemplateInstantiateExpr.cpp | 3 +- lib/Sema/SemaTemplateInstantiateStmt.cpp | 8 +- test/Analysis/ptr-arith.c | 2 +- test/Analysis/retain-release-gc-only.m | 49 + test/Analysis/retain-release.m | 28 +- test/CMakeLists.txt | 53 + test/CodeGen/attributes.c | 12 +- test/CodeGen/x86_64-arguments.c | 6 + test/CodeGenObjC/blocks-3.m | 15 + test/Driver/flags.c | 6 +- test/Driver/redzone.c | 6 + test/Parser/pragma-weak.c | 17 + test/Sema/const-eval.c | 1 + test/SemaObjCXX/references.mm | 27 + test/SemaTemplate/ackermann.cpp | 37 + test/SemaTemplate/default-arguments.cpp | 3 + test/SemaTemplate/temp_class_spec.cpp | 84 ++ tools/clang-cc/clang-cc.cpp | 31 +- utils/test/MultiTestRunner.py | 9 +- www/menu.html.incl | 9 +- 92 files changed, 3306 insertions(+), 1884 deletions(-) create mode 100644 lib/CodeGen/TargetABIInfo.cpp create mode 100644 lib/Sema/SemaTemplateDeduction.cpp create mode 100644 test/CMakeLists.txt create mode 100644 test/CodeGenObjC/blocks-3.m create mode 100644 test/Driver/redzone.c create mode 100644 test/Parser/pragma-weak.c create mode 100644 test/SemaObjCXX/references.mm create mode 100644 test/SemaTemplate/ackermann.cpp 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 = ""; tabWidth = 2; }; 03F50AC50D416EAA00B9CF60 /* Targets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = Targets.cpp; sourceTree = ""; tabWidth = 2; }; + 1A14D3A60FD78A3F00DA2835 /* DeclPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclPrinter.cpp; path = lib/AST/DeclPrinter.cpp; sourceTree = ""; tabWidth = 2; }; 1A2193CB0F45EEB700C0713D /* ABIInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = ABIInfo.h; path = lib/CodeGen/ABIInfo.h; sourceTree = ""; tabWidth = 2; }; 1A2193CC0F45EEB700C0713D /* Mangle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = Mangle.cpp; path = lib/CodeGen/Mangle.cpp; sourceTree = ""; tabWidth = 2; }; 1A2193CD0F45EEB700C0713D /* Mangle.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Mangle.h; path = lib/CodeGen/Mangle.h; sourceTree = ""; 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 = ""; tabWidth = 2; }; 1A410F840FBCE51100351440 /* SemaTemplateInstantiateExpr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateExpr.cpp; path = lib/Sema/SemaTemplateInstantiateExpr.cpp; sourceTree = ""; tabWidth = 2; }; 1A471AB40F437BC500753CE8 /* CGBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBlocks.cpp; path = lib/CodeGen/CGBlocks.cpp; sourceTree = ""; tabWidth = 2; }; - 1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateStmt.cpp; path = lib/Sema/SemaTemplateInstantiateStmt.cpp; sourceTree = ""; }; + 1A5119C30FBDF71000A1FF22 /* SemaTemplateInstantiateStmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateStmt.cpp; path = lib/Sema/SemaTemplateInstantiateStmt.cpp; sourceTree = ""; tabWidth = 2; }; 1A5D5E570E5E81010023C059 /* CGCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXX.cpp; path = lib/CodeGen/CGCXX.cpp; sourceTree = ""; tabWidth = 2; }; 1A649E1D0F9599D9005B965E /* CGBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGBlocks.h; path = lib/CodeGen/CGBlocks.h; sourceTree = ""; }; 1A649E1E0F9599DA005B965E /* CGCXX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGCXX.h; path = lib/CodeGen/CGCXX.h; sourceTree = ""; }; 1A68BC110D0CADDD001A28C8 /* PPCBuiltins.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = PPCBuiltins.def; path = clang/AST/PPCBuiltins.def; sourceTree = ""; tabWidth = 2; }; 1A68BC120D0CADDD001A28C8 /* TargetBuiltins.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = TargetBuiltins.h; path = clang/AST/TargetBuiltins.h; sourceTree = ""; tabWidth = 2; }; 1A68BC130D0CADDD001A28C8 /* X86Builtins.def */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = text; name = X86Builtins.def; path = clang/AST/X86Builtins.def; sourceTree = ""; tabWidth = 2; }; - 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXTemp.cpp; path = lib/CodeGen/CGCXXTemp.cpp; sourceTree = ""; }; + 1A6FE7080FD6F85800E00CA9 /* CGCXXTemp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGCXXTemp.cpp; path = lib/CodeGen/CGCXXTemp.cpp; sourceTree = ""; tabWidth = 2; }; 1A7019E90F79BC1100FEC4D1 /* DiagnosticAnalysisKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticAnalysisKinds.td; sourceTree = ""; }; 1A7019EA0F79BC1100FEC4D1 /* DiagnosticASTKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticASTKinds.td; sourceTree = ""; }; 1A7019EB0F79BC1100FEC4D1 /* DiagnosticCommonKinds.td */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DiagnosticCommonKinds.td; sourceTree = ""; }; @@ -489,6 +492,7 @@ 90FB99DE0F98FB1D008F9415 /* DeclContextInternals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclContextInternals.h; path = clang/AST/DeclContextInternals.h; sourceTree = ""; }; 90FB99DF0F98FB1D008F9415 /* DeclVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeclVisitor.h; path = clang/AST/DeclVisitor.h; sourceTree = ""; }; 90FB99E00F98FB1D008F9415 /* ExternalASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExternalASTSource.h; path = clang/AST/ExternalASTSource.h; sourceTree = ""; }; + BDF87CF60FD746F300BBF872 /* SemaTemplateDeduction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateDeduction.cpp; path = lib/Sema/SemaTemplateDeduction.cpp; sourceTree = ""; tabWidth = 2; }; DE01DA480B12ADA300AC22CE /* PPCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PPCallbacks.h; sourceTree = ""; }; DE06756B0C051CFE00EBBFD8 /* ParseExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = ParseExprCXX.cpp; path = lib/Parse/ParseExprCXX.cpp; sourceTree = ""; tabWidth = 2; }; DE06B73D0A8307640050E87E /* LangOptions.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = LangOptions.h; sourceTree = ""; tabWidth = 2; }; @@ -595,7 +599,7 @@ DEAEE98A0A5A2B970045101B /* MultipleIncludeOpt.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MultipleIncludeOpt.h; sourceTree = ""; }; DEAEED4A0A5AF89A0045101B /* NOTES.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = NOTES.txt; sourceTree = ""; }; DEB076C90F3A221200F5A2BE /* DeclTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = DeclTemplate.h; path = clang/AST/DeclTemplate.h; sourceTree = ""; tabWidth = 2; }; - DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeclTemplate.cpp; path = lib/AST/DeclTemplate.cpp; sourceTree = ""; }; + DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = DeclTemplate.cpp; path = lib/AST/DeclTemplate.cpp; sourceTree = ""; tabWidth = 2; }; DEB077930F44F96000F5A2BE /* TokenConcatenation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TokenConcatenation.h; sourceTree = ""; }; DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenConcatenation.cpp; sourceTree = ""; }; DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAttr.cpp; path = lib/Sema/SemaAttr.cpp; sourceTree = ""; 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 = ""; tabWidth = 2; }; DEC8D9A30A94346E00353FCA /* AST.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AST.h; path = clang/AST/AST.h; sourceTree = ""; tabWidth = 2; }; DECAB0CF0DB3C84200E13CCB /* RewriteRope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RewriteRope.cpp; path = lib/Rewrite/RewriteRope.cpp; sourceTree = ""; }; - DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JumpDiagnostics.cpp; path = lib/Sema/JumpDiagnostics.cpp; sourceTree = ""; }; + DECB6D640F9AE26600F5FBC7 /* JumpDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = JumpDiagnostics.cpp; path = lib/Sema/JumpDiagnostics.cpp; sourceTree = ""; tabWidth = 2; }; DECB6F030F9D939A00F5FBC7 /* InitPreprocessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InitPreprocessor.h; path = clang/Frontend/InitPreprocessor.h; sourceTree = ""; }; DECB6F060F9D93A800F5FBC7 /* InitPreprocessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitPreprocessor.cpp; path = lib/Frontend/InitPreprocessor.cpp; sourceTree = ""; }; DECB734E0FA3ED8400F5FBC7 /* StmtObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StmtObjC.h; path = clang/AST/StmtObjC.h; sourceTree = ""; }; @@ -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 @@ - - -Precompiled Headers (PCH) + + + Precompiled Headers (PCH) + + + @@ -33,7 +40,9 @@
  • Method Pool Block
  • - +
  • Precompiled Header Integration + Points
  • +

    Using Precompiled Headers with clang-cc

    @@ -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.

    +the header itself.

    + +

    When given the -print-stats 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 Cocoa.h header (which is built as a precompiled +header), this option illustrates how little of the actual precompiled +header is required:

    + +
    +*** 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
    +
    + +

    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.

    Precompiled Header Contents

    @@ -117,6 +156,14 @@ either a block or a record within . The contents of each of these logical blocks are described below.

    +

    For a given precompiled header, the llvm-bcanalyzer +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.

    +

    Metadata Block

    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.

    -

    +

    Precompiled Header Integration Points

    + +

    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.

    + +

    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 PCHReader +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. PCHReader implements the +following abstract classes:

    + +
    +
    StatSysCallCache
    +
    This abstract interface is associated with the + FileManager class, and is used whenever the file + manager is going to perform a stat() system call.
    + +
    ExternalSLocEntrySource
    +
    This abstract interface is associated with the + SourceManager class, and is used whenever the + source manager needs to load the details + of a file, buffer, or macro instantiation.
    + +
    IdentifierInfoLookup
    +
    This abstract interface is associated with the + IdentifierTable 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 identifier table + to load any top-level declarations or macros associated with that + identifier.
    + +
    ExternalASTSource
    +
    This abstract interface is associated with the + ASTContext 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).
    + +
    ExternalSemaSource
    +
    This abstract interface is associated with the Sema + class, and is used whenever semantic analysis needs to read + information from the global method + pool.
    +
    + + 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).

    -

    Clang supports an implementation of precompiled headers known as -pre-tokenized headers (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 PTH Internals - document.

    +

    Generating a PCH File

    -

    Generating a PTH File

    - -

    To generate a PTH file using Clang, one invokes Clang with +

    To generate a PCH file using Clang, one invokes Clang with the -x <language>-header option. This mirrors the interface in GCC for generating PCH files:

       $ 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
     
    -

    Using a PTH File

    +

    Using a PCH File

    -

    A PTH file can then be used as a prefix header when a +

    A PCH file can then be used as a prefix header when a -include option is passed to clang:

       $ clang -include test.h test.c -o test
     
    -

    The clang driver will first check if a PTH file for test.h +

    The clang driver will first check if a PCH file for test.h is available; if so, the contents of test.h (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 test.h. This mirrors the behavior of GCC.

    -

    NOTE: Clang does not automatically use PTH files +

    NOTE: Clang does not automatically use PCH files for headers that are directly included within a source file. For example:

    -  $ 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
     
    -

    In this example, clang will not automatically use the PTH file for +

    In this example, clang will not automatically use the PCH file for test.h since test.h was included directly in the source file and not specified on the command line using -include.

    @@ -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.

    +

    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.

    +

    Microsoft extensions

    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 &Fields); - + + void ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl &Ivars, + bool CollectSynthesized = true); void CollectSynthesizedIvars(const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl &Ivars); void CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD, llvm::SmallVectorImpl &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 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 PackHandler; llvm::OwningPtr UnusedHandler; + llvm::OwningPtr 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 &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 &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 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 Ivars; - CollectSynthesizedIvars(D, Ivars); - for (unsigned k = 0, e = Ivars.size(); k != e; ++k) - NewEntry->LayoutField(Ivars[k], i++, false, StructPacking, *this); - } - + llvm::SmallVector 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(*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(Param)) { + + QualType ParamType = + Context.getTypeDeclType(const_cast(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(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::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()) { Summ.setRetEffect(ObjCAllocRetE); } - else if (FD->getAttr()) { + else if (FD->getAttr()) { + Summ.setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true)); + } + } + else if (RetTy->getAsPointerType()) { + if (FD->getAttr()) { 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 &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 &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 + 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 AssignCache; + std::map 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; igetElementType(), 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(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 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 &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(); 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 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 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 &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(ID->getClassInterface()); llvm::SmallVector 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 &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 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 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 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 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()) { GV->setLinkage(llvm::Function::DLLExportLinkage); - } else if (D->hasAttr() || D->hasAttr()) { + } else if (D->hasAttr()) { 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()) GV->setLinkage(llvm::Function::DLLExportLinkage); - else if (D->hasAttr() || D->hasAttr()) + else if (D->hasAttr()) 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(*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; igetElementType(), 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(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 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 &Buf, const char *Macro, - const char *Command = "#define ") { +static void DefineBuiltinMacro(std::vector &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 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 &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 *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 &Deduced); - bool DeduceTemplateArguments(const TemplateArgument &Param, - const TemplateArgument &Arg, - llvm::SmallVectorImpl &Deduced); - bool DeduceTemplateArguments(const TemplateArgumentList &ParamList, - const TemplateArgumentList &ArgList, - llvm::SmallVectorImpl &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(); + DeclContext *EnclosingContext; + if (ObjCImplementationDecl *IMPDecl = + dyn_cast(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(IDecl); + } + else + EnclosingContext = dyn_cast(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(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(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(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 &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(TagD.getAs()), Context, Decls); + llvm::SmallVector 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(TagD.getAs()); + 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::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(); - - 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 ConvertedTemplateArgs; + TemplateArgumentListBuilder ConvertedTemplateArgs(Context); if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, TemplateArgs, NumTemplateArgs, RAngleLoc, ConvertedTemplateArgs)) @@ -829,15 +835,16 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // template 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(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 &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(*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(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 *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 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 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 &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 &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 &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 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(E)) + E = IC->getSubExpr(); + + if (DeclRefExpr *DRE = dyn_cast(E)) + return dyn_cast(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 &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 &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 &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(Param)->getPointeeType(), + PointerArg->getPointeeType(), + Deduced); + } + + // T & + case Type::LValueReference: { + const LValueReferenceType *ReferenceArg = Arg->getAsLValueReferenceType(); + if (!ReferenceArg) + return false; + + return DeduceTemplateArguments(Context, + cast(Param)->getPointeeType(), + ReferenceArg->getPointeeType(), + Deduced); + } + + // T && [C++0x] + case Type::RValueReference: { + const RValueReferenceType *ReferenceArg = Arg->getAsRValueReferenceType(); + if (!ReferenceArg) + return false; + + return DeduceTemplateArguments(Context, + cast(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(Arg); + if (!ArrayArg) + return false; + + // Check the element type of the arrays + const DependentSizedArrayType *DependentArrayParm + = cast(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(ArrayArg)) + return DeduceNonTypeTemplateArgument(Context, NTTP, + ConstantArrayArg->getSize(), + Deduced); + if (const DependentSizedArrayType *DependentArrayArg + = dyn_cast(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 &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 &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 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(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 Matched; + typedef std::pair MatchResult; + llvm::SmallVector Matched; for (llvm::FoldingSet::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 {} +- (Class)class; + (id)alloc; + (id)allocWithZone:(NSZone *)zone; @end typedef float CGFloat; @@ -173,6 +176,28 @@ void f5b() { @end //===----------------------------------------------------------------------===// +// 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}} } -//< %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 +// struct Ackermann { +// enum { +// value = M ? (N ? Ackermann >::value +// : Ackermann::value) +// : N + 1 +// }; +// }; + +template +struct Ackermann { + enum { + value = Ackermann::value >::value + }; +}; + +template struct Ackermann { + enum { + value = Ackermann::value + }; +}; + +template 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 struct X; X<> *x4; + +template 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::value? -1 : 1]; int array1[is_pointer::value? 1 : -1]; int array2[is_pointer::value? 1 : -1]; // expected-error{{partial ordering}} \ // expected-error{{negative}} + +template +struct is_lvalue_reference { + static const bool value = false; +}; + +template +struct is_lvalue_reference { + static const bool value = true; +}; + +int lvalue_ref0[is_lvalue_reference::value? -1 : 1]; +int lvalue_ref1[is_lvalue_reference::value? 1 : -1]; + +template +struct is_same { + static const bool value = false; +}; + +template +struct is_same { + static const bool value = true; +}; + +typedef int INT; +typedef INT* int_ptr; + +int is_same0[is_same::value? 1 : -1]; +int is_same1[is_same::value? 1 : -1]; +int is_same2[is_same::value? -1 : 1]; +int is_same3[is_same::value? -1 : 1]; + +template +struct remove_reference { + typedef T type; +}; + +template +struct remove_reference { + typedef T type; +}; + +int remove_ref0[is_same::type, int>::value? 1 : -1]; +int remove_ref1[is_same::type, int>::value? 1 : -1]; + +template +struct is_incomplete_array { + static const bool value = false; +}; + +template +struct is_incomplete_array { + static const bool value = true; +}; + +int incomplete_array0[is_incomplete_array::value ? -1 : 1]; +int incomplete_array1[is_incomplete_array::value ? -1 : 1]; +int incomplete_array2[is_incomplete_array::value ? 1 : -1]; +int incomplete_array3[is_incomplete_array::value ? 1 : -1]; + +template +struct is_array_with_4_elements { + static const bool value = false; +}; + +template +struct is_array_with_4_elements { + static const bool value = true; +}; + +int array_with_4_elements0[is_array_with_4_elements::value ? -1 : 1]; +int array_with_4_elements1[is_array_with_4_elements::value ? -1 : 1]; +int array_with_4_elements2[is_array_with_4_elements::value ? 1 : -1]; +int array_with_4_elements3[is_array_with_4_elements::value ? 1 : -1]; + +template +struct get_array_size; + +template +struct get_array_size { + static const unsigned value = N; +}; + +int array_size0[get_array_size::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 +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 +CharIsSigned("fsigned-char", + llvm::cl::desc("Force char to be a signed/unsigned type")); static llvm::cl::opt @@ -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 TargetFeatures("target-feature", llvm::cl::desc("Target specific attributes")); + +static llvm::cl::opt +DisableRedZone("disable-red-zone", + llvm::cl::desc("Do not emit code that uses the red zone."), + llvm::cl::init(false)); + +static llvm::cl::opt +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 @@ About Features Comparisons + Users Manual + Language Extensions + C++ Status + + +