diff options
author | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2014-03-21 17:53:59 +0000 |
commit | 9cedb8bb69b89b0f0c529937247a6a80cabdbaec (patch) | |
tree | c978f0e9ec1ab92dc8123783f30b08a7fd1e2a39 /contrib/llvm/tools/clang/utils/TableGen | |
parent | 03fdc2934eb61c44c049a02b02aa974cfdd8a0eb (diff) | |
download | FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.zip FreeBSD-src-9cedb8bb69b89b0f0c529937247a6a80cabdbaec.tar.gz |
MFC 261991:
Upgrade our copy of llvm/clang to 3.4 release. This version supports
all of the features in the current working draft of the upcoming C++
standard, provisionally named C++1y.
The code generator's performance is greatly increased, and the loop
auto-vectorizer is now enabled at -Os and -O2 in addition to -O3. The
PowerPC backend has made several major improvements to code generation
quality and compile time, and the X86, SPARC, ARM32, Aarch64 and SystemZ
backends have all seen major feature work.
Release notes for llvm and clang can be found here:
<http://llvm.org/releases/3.4/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html>
MFC 262121 (by emaste):
Update lldb for clang/llvm 3.4 import
This commit largely restores the lldb source to the upstream r196259
snapshot with the addition of threaded inferior support and a few bug
fixes.
Specific upstream lldb revisions restored include:
SVN git
181387 779e6ac
181703 7bef4e2
182099 b31044e
182650 f2dcf35
182683 0d91b80
183862 15c1774
183929 99447a6
184177 0b2934b
184948 4dc3761
184954 007e7bc
186990 eebd175
Sponsored by: DARPA, AFRL
MFC 262186 (by emaste):
Fix mismerge in r262121
A break statement was lost in the merge. The error had no functional
impact, but restore it to reduce the diff against upstream.
MFC 262303:
Pull in r197521 from upstream clang trunk (by rdivacky):
Use the integrated assembler by default on FreeBSD/ppc and ppc64.
Requested by: jhibbits
MFC 262611:
Pull in r196874 from upstream llvm trunk:
Fix a crash that occurs when PWD is invalid.
MCJIT needs to be able to run in hostile environments, even when PWD
is invalid. There's no need to crash MCJIT in this case.
The obvious fix is to simply leave MCContext's CompilationDir empty
when PWD can't be determined. This way, MCJIT clients,
and other clients that link with LLVM don't need a valid working directory.
If we do want to guarantee valid CompilationDir, that should be done
only for clients of getCompilationDir(). This is as simple as checking
for an empty string.
The only current use of getCompilationDir is EmitGenDwarfInfo, which
won't conceivably run with an invalid working dir. However, in the
purely hypothetically and untestable case that this happens, the
AT_comp_dir will be omitted from the compilation_unit DIE.
This should help fix assertions occurring with ports-mgmt/tinderbox,
when it is using jails, and sometimes invalidates clang's current
working directory.
Reported by: decke
MFC 262809:
Pull in r203007 from upstream clang trunk:
Don't produce an alias between destructors with different calling conventions.
Fixes pr19007.
(Please note that is an LLVM PR identifier, not a FreeBSD one.)
This should fix Firefox and/or libxul crashes (due to problems with
regparm/stdcall calling conventions) on i386.
Reported by: multiple users on freebsd-current
PR: bin/187103
MFC 263048:
Repair recognition of "CC" as an alias for the C++ compiler, since it
was silently broken by upstream for a Windows-specific use-case.
Apparently some versions of CMake still rely on this archaic feature...
Reported by: rakuco
MFC 263049:
Garbage collect the old way of adding the libstdc++ include directories
in clang's InitHeaderSearch.cpp. This has been superseded by David
Chisnall's commit in r255321.
Moreover, if libc++ is used, the libstdc++ include directories should
not be in the search path at all. These directories are now only used
if you pass -stdlib=libstdc++.
Diffstat (limited to 'contrib/llvm/tools/clang/utils/TableGen')
7 files changed, 1864 insertions, 684 deletions
diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp index eaf10a6..653d7b7 100644 --- a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/StringMatcher.h" #include "llvm/TableGen/TableGenBackend.h" @@ -46,7 +47,7 @@ static std::string ReadPCHRecord(StringRef type) { return StringSwitch<std::string>(type) .EndsWith("Decl *", "GetLocalDeclAs<" + std::string(type, 0, type.size()-1) + ">(F, Record[Idx++])") - .Case("QualType", "getLocalType(F, Record[Idx++])") + .Case("TypeSourceInfo *", "GetTypeSourceInfo(F, Record, Idx)") .Case("Expr *", "ReadExpr(F)") .Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)") .Case("SourceLocation", "ReadSourceLocation(F, Record, Idx)") @@ -58,7 +59,8 @@ static std::string WritePCHRecord(StringRef type, StringRef name) { return StringSwitch<std::string>(type) .EndsWith("Decl *", "AddDeclRef(" + std::string(name) + ", Record);\n") - .Case("QualType", "AddTypeRef(" + std::string(name) + ", Record);\n") + .Case("TypeSourceInfo *", + "AddTypeSourceInfo(" + std::string(name) + ", Record);\n") .Case("Expr *", "AddStmt(" + std::string(name) + ");\n") .Case("IdentifierInfo *", "AddIdentifierRef(" + std::string(name) + ", Record);\n") @@ -95,11 +97,12 @@ namespace { class Argument { std::string lowerName, upperName; StringRef attrName; + bool isOpt; public: Argument(Record &Arg, StringRef Attr) : lowerName(Arg.getValueAsString("Name")), upperName(lowerName), - attrName(Attr) { + attrName(Attr), isOpt(false) { if (!lowerName.empty()) { lowerName[0] = std::tolower(lowerName[0]); upperName[0] = std::toupper(upperName[0]); @@ -111,6 +114,9 @@ namespace { StringRef getUpperName() const { return upperName; } StringRef getAttrName() const { return attrName; } + bool isOptional() const { return isOpt; } + void setOptional(bool set) { isOpt = set; } + // These functions print the argument contents formatted in different ways. virtual void writeAccessors(raw_ostream &OS) const = 0; virtual void writeAccessorDefinitions(raw_ostream &OS) const {} @@ -119,6 +125,7 @@ namespace { virtual void writeTemplateInstantiation(raw_ostream &OS) const {} virtual void writeCtorBody(raw_ostream &OS) const {} virtual void writeCtorInitializers(raw_ostream &OS) const = 0; + virtual void writeCtorDefaultInitializers(raw_ostream &OS) const = 0; virtual void writeCtorParameters(raw_ostream &OS) const = 0; virtual void writeDeclarations(raw_ostream &OS) const = 0; virtual void writePCHReadArgs(raw_ostream &OS) const = 0; @@ -128,6 +135,9 @@ namespace { virtual void writeDump(raw_ostream &OS) const = 0; virtual void writeDumpChildren(raw_ostream &OS) const {} virtual void writeHasChildren(raw_ostream &OS) const { OS << "false"; } + + virtual bool isEnumArg() const { return false; } + virtual bool isVariadicEnumArg() const { return false; } }; class SimpleArgument : public Argument { @@ -154,6 +164,9 @@ namespace { void writeCtorInitializers(raw_ostream &OS) const { OS << getLowerName() << "(" << getUpperName() << ")"; } + void writeCtorDefaultInitializers(raw_ostream &OS) const { + OS << getLowerName() << "()"; + } void writeCtorParameters(raw_ostream &OS) const { OS << type << " " << getUpperName(); } @@ -173,10 +186,11 @@ namespace { } void writeValue(raw_ostream &OS) const { if (type == "FunctionDecl *") { - OS << "\" << get" << getUpperName() << "()->getNameInfo().getAsString() << \""; + OS << "\" << get" << getUpperName() + << "()->getNameInfo().getAsString() << \""; } else if (type == "IdentifierInfo *") { OS << "\" << get" << getUpperName() << "()->getName() << \""; - } else if (type == "QualType") { + } else if (type == "TypeSourceInfo *") { OS << "\" << get" << getUpperName() << "().getAsString() << \""; } else if (type == "SourceLocation") { OS << "\" << get" << getUpperName() << "().getRawEncoding() << \""; @@ -191,7 +205,7 @@ namespace { } else if (type == "IdentifierInfo *") { OS << " OS << \" \" << SA->get" << getUpperName() << "()->getName();\n"; - } else if (type == "QualType") { + } else if (type == "TypeSourceInfo *") { OS << " OS << \" \" << SA->get" << getUpperName() << "().getAsString();\n"; } else if (type == "SourceLocation") { @@ -246,6 +260,9 @@ namespace { << getLowerName() << "(new (Ctx, 1) char[" << getLowerName() << "Length])"; } + void writeCtorDefaultInitializers(raw_ostream &OS) const { + OS << getLowerName() << "Length(0)," << getLowerName() << "(0)"; + } void writeCtorParameters(raw_ostream &OS) const { OS << "llvm::StringRef " << getUpperName(); } @@ -347,6 +364,9 @@ namespace { void writeCtorInitializers(raw_ostream &OS) const { OS << "is" << getLowerName() << "Expr(Is" << getUpperName() << "Expr)"; } + void writeCtorDefaultInitializers(raw_ostream &OS) const { + OS << "is" << getLowerName() << "Expr(false)"; + } void writeCtorParameters(raw_ostream &OS) const { OS << "bool Is" << getUpperName() << "Expr, void *" << getUpperName(); } @@ -440,6 +460,9 @@ namespace { << getLowerName() << "(new (Ctx, 16) " << getType() << "[" << getLowerName() << "Size])"; } + void writeCtorDefaultInitializers(raw_ostream &OS) const { + OS << getLowerName() << "Size(0), " << getLowerName() << "(0)"; + } void writeCtorParameters(raw_ostream &OS) const { OS << getType() << " *" << getUpperName() << ", unsigned " << getUpperName() << "Size"; @@ -454,7 +477,7 @@ namespace { << ";\n"; OS << " " << getLowerName() << ".reserve(" << getLowerName() << "Size);\n"; - OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n"; + OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n"; std::string read = ReadPCHRecord(type); OS << " " << getLowerName() << ".push_back(" << read << ");\n"; @@ -506,6 +529,8 @@ namespace { assert(!uniques.empty()); } + bool isEnumArg() const { return true; } + void writeAccessors(raw_ostream &OS) const { OS << " " << type << " get" << getUpperName() << "() const {\n"; OS << " return " << getLowerName() << ";\n"; @@ -520,6 +545,9 @@ namespace { void writeCtorInitializers(raw_ostream &OS) const { OS << getLowerName() << "(" << getUpperName() << ")"; } + void writeCtorDefaultInitializers(raw_ostream &OS) const { + OS << getLowerName() << "(" << type << "(0))"; + } void writeCtorParameters(raw_ostream &OS) const { OS << type << " " << getUpperName(); } @@ -562,6 +590,109 @@ namespace { } OS << " }\n"; } + + void writeConversion(raw_ostream &OS) const { + OS << " static bool ConvertStrTo" << type << "(StringRef Val, "; + OS << type << " &Out) {\n"; + OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<"; + OS << type << "> >(Val)\n"; + for (size_t I = 0; I < enums.size(); ++I) { + OS << " .Case(\"" << values[I] << "\", "; + OS << getAttrName() << "Attr::" << enums[I] << ")\n"; + } + OS << " .Default(Optional<" << type << ">());\n"; + OS << " if (R) {\n"; + OS << " Out = *R;\n return true;\n }\n"; + OS << " return false;\n"; + OS << " }\n"; + } + }; + + class VariadicEnumArgument: public VariadicArgument { + std::string type, QualifiedTypeName; + std::vector<StringRef> values, enums, uniques; + public: + VariadicEnumArgument(Record &Arg, StringRef Attr) + : VariadicArgument(Arg, Attr, Arg.getValueAsString("Type")), + type(Arg.getValueAsString("Type")), + values(getValueAsListOfStrings(Arg, "Values")), + enums(getValueAsListOfStrings(Arg, "Enums")), + uniques(enums) + { + // Calculate the various enum values + std::sort(uniques.begin(), uniques.end()); + uniques.erase(std::unique(uniques.begin(), uniques.end()), uniques.end()); + + QualifiedTypeName = getAttrName().str() + "Attr::" + type; + + // FIXME: Emit a proper error + assert(!uniques.empty()); + } + + bool isVariadicEnumArg() const { return true; } + + void writeDeclarations(raw_ostream &OS) const { + std::vector<StringRef>::const_iterator i = uniques.begin(), + e = uniques.end(); + // The last one needs to not have a comma. + --e; + + OS << "public:\n"; + OS << " enum " << type << " {\n"; + for (; i != e; ++i) + OS << " " << *i << ",\n"; + OS << " " << *e << "\n"; + OS << " };\n"; + OS << "private:\n"; + + VariadicArgument::writeDeclarations(OS); + } + void writeDump(raw_ostream &OS) const { + OS << " for (" << getAttrName() << "Attr::" << getLowerName() + << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" + << getLowerName() << "_end(); I != E; ++I) {\n"; + OS << " switch(*I) {\n"; + for (std::vector<StringRef>::const_iterator UI = uniques.begin(), + UE = uniques.end(); UI != UE; ++UI) { + OS << " case " << getAttrName() << "Attr::" << *UI << ":\n"; + OS << " OS << \" " << *UI << "\";\n"; + OS << " break;\n"; + } + OS << " }\n"; + OS << " }\n"; + } + void writePCHReadDecls(raw_ostream &OS) const { + OS << " unsigned " << getLowerName() << "Size = Record[Idx++];\n"; + OS << " SmallVector<" << QualifiedTypeName << ", 4> " << getLowerName() + << ";\n"; + OS << " " << getLowerName() << ".reserve(" << getLowerName() + << "Size);\n"; + OS << " for (unsigned i = " << getLowerName() << "Size; i; --i)\n"; + OS << " " << getLowerName() << ".push_back(" << "static_cast<" + << QualifiedTypeName << ">(Record[Idx++]));\n"; + } + void writePCHWrite(raw_ostream &OS) const{ + OS << " Record.push_back(SA->" << getLowerName() << "_size());\n"; + OS << " for (" << getAttrName() << "Attr::" << getLowerName() + << "_iterator i = SA->" << getLowerName() << "_begin(), e = SA->" + << getLowerName() << "_end(); i != e; ++i)\n"; + OS << " " << WritePCHRecord(QualifiedTypeName, "(*i)"); + } + void writeConversion(raw_ostream &OS) const { + OS << " static bool ConvertStrTo" << type << "(StringRef Val, "; + OS << type << " &Out) {\n"; + OS << " Optional<" << type << "> R = llvm::StringSwitch<Optional<"; + OS << type << "> >(Val)\n"; + for (size_t I = 0; I < enums.size(); ++I) { + OS << " .Case(\"" << values[I] << "\", "; + OS << getAttrName() << "Attr::" << enums[I] << ")\n"; + } + OS << " .Default(Optional<" << type << ">());\n"; + OS << " if (R) {\n"; + OS << " Out = *R;\n return true;\n }\n"; + OS << " return false;\n"; + OS << " }\n"; + } }; class VersionArgument : public Argument { @@ -590,6 +721,9 @@ namespace { void writeCtorInitializers(raw_ostream &OS) const { OS << getLowerName() << "(" << getUpperName() << ")"; } + void writeCtorDefaultInitializers(raw_ostream &OS) const { + OS << getLowerName() << "()"; + } void writeCtorParameters(raw_ostream &OS) const { OS << "VersionTuple " << getUpperName(); } @@ -695,6 +829,29 @@ namespace { << "SA->" << getLowerName() << "_end()"; } }; + + class TypeArgument : public SimpleArgument { + public: + TypeArgument(Record &Arg, StringRef Attr) + : SimpleArgument(Arg, Attr, "TypeSourceInfo *") + {} + + void writeAccessors(raw_ostream &OS) const { + OS << " QualType get" << getUpperName() << "() const {\n"; + OS << " return " << getLowerName() << "->getType();\n"; + OS << " }"; + OS << " " << getType() << " get" << getUpperName() << "Loc() const {\n"; + OS << " return " << getLowerName() << ";\n"; + OS << " }"; + } + void writeTemplateInstantiationArgs(raw_ostream &OS) const { + OS << "A->get" << getUpperName() << "Loc()"; + } + void writePCHWrite(raw_ostream &OS) const { + OS << " " << WritePCHRecord( + getType(), "SA->get" + std::string(getUpperName()) + "Loc()"); + } + }; } static Argument *createArgument(Record &Arg, StringRef Attr, @@ -716,14 +873,15 @@ static Argument *createArgument(Record &Arg, StringRef Attr, "bool"); else if (ArgName == "IntArgument") Ptr = new SimpleArgument(Arg, Attr, "int"); else if (ArgName == "StringArgument") Ptr = new StringArgument(Arg, Attr); - else if (ArgName == "TypeArgument") - Ptr = new SimpleArgument(Arg, Attr, "QualType"); + else if (ArgName == "TypeArgument") Ptr = new TypeArgument(Arg, Attr); else if (ArgName == "UnsignedArgument") Ptr = new SimpleArgument(Arg, Attr, "unsigned"); else if (ArgName == "SourceLocArgument") Ptr = new SimpleArgument(Arg, Attr, "SourceLocation"); else if (ArgName == "VariadicUnsignedArgument") Ptr = new VariadicArgument(Arg, Attr, "unsigned"); + else if (ArgName == "VariadicEnumArgument") + Ptr = new VariadicEnumArgument(Arg, Attr); else if (ArgName == "VariadicExprArgument") Ptr = new VariadicExprArgument(Arg, Attr); else if (ArgName == "VersionArgument") @@ -738,6 +896,10 @@ static Argument *createArgument(Record &Arg, StringRef Attr, break; } } + + if (Ptr && Arg.getValueAsBit("Optional")) + Ptr->setOptional(true); + return Ptr; } @@ -892,7 +1054,15 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { if (!R.getValueAsBit("ASTNode")) continue; - const std::string &SuperName = R.getSuperClasses().back()->getName(); + const std::vector<Record *> Supers = R.getSuperClasses(); + assert(!Supers.empty() && "Forgot to specify a superclass for the attr"); + std::string SuperName; + for (std::vector<Record *>::const_reverse_iterator I = Supers.rbegin(), + E = Supers.rend(); I != E; ++I) { + const Record &R = **I; + if (R.getName() != "TargetSpecificAttr" && SuperName.empty()) + SuperName = R.getName(); + } OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n"; @@ -918,10 +1088,13 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { OS << "\n public:\n"; OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n"; + bool HasOpt = false; for (ai = Args.begin(); ai != ae; ++ai) { OS << " , "; (*ai)->writeCtorParameters(OS); OS << "\n"; + if ((*ai)->isOptional()) + HasOpt = true; } OS << " , "; @@ -944,6 +1117,41 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { } OS << " }\n\n"; + // If there are optional arguments, write out a constructor that elides the + // optional arguments as well. + if (HasOpt) { + OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n"; + for (ai = Args.begin(); ai != ae; ++ai) { + if (!(*ai)->isOptional()) { + OS << " , "; + (*ai)->writeCtorParameters(OS); + OS << "\n"; + } + } + + OS << " , "; + OS << "unsigned SI = 0\n"; + + OS << " )\n"; + OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n"; + + for (ai = Args.begin(); ai != ae; ++ai) { + OS << " , "; + (*ai)->writeCtorDefaultInitializers(OS); + OS << "\n"; + } + + OS << " {\n"; + + for (ai = Args.begin(); ai != ae; ++ai) { + if (!(*ai)->isOptional()) { + (*ai)->writeCtorBody(OS); + OS << "\n"; + } + } + OS << " }\n\n"; + } + OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n"; OS << " virtual void printPretty(raw_ostream &OS,\n" << " const PrintingPolicy &Policy) const;\n"; @@ -953,6 +1161,14 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { for (ai = Args.begin(); ai != ae; ++ai) { (*ai)->writeAccessors(OS); OS << "\n\n"; + + if ((*ai)->isEnumArg()) { + EnumArgument *EA = (EnumArgument *)*ai; + EA->writeConversion(OS); + } else if ((*ai)->isVariadicEnumArg()) { + VariadicEnumArgument *VEA = (VariadicEnumArgument *)*ai; + VEA->writeConversion(OS); + } } OS << R.getValueAsString("AdditionalMembers"); @@ -971,44 +1187,69 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) { OS << "#endif\n"; } -// Emits the all-arguments-are-expressions property for attributes. -void EmitClangAttrExprArgsList(RecordKeeper &Records, raw_ostream &OS) { - emitSourceFileHeader("llvm::StringSwitch code to match attributes with " - "expression arguments", OS); +static bool isIdentifierArgument(Record *Arg) { + return !Arg->getSuperClasses().empty() && + llvm::StringSwitch<bool>(Arg->getSuperClasses().back()->getName()) + .Case("IdentifierArgument", true) + .Case("EnumArgument", true) + .Default(false); +} - std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); +/// \brief Emits the first-argument-is-type property for attributes. +void EmitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("llvm::StringSwitch code to match attributes with a " + "type argument", OS); - for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); + std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); + + for (std::vector<Record *>::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { Record &Attr = **I; - // Determine whether the first argument is something that is always - // an expression. + // Determine whether the first argument is a type. std::vector<Record *> Args = Attr.getValueAsListOfDefs("Args"); - if (Args.empty() || Args[0]->getSuperClasses().empty()) + if (Args.empty()) continue; - // Check whether this is one of the argument kinds that implies an - // expression. - // FIXME: Aligned is weird. - if (!llvm::StringSwitch<bool>(Args[0]->getSuperClasses().back()->getName()) - .Case("AlignedArgument", true) - .Case("BoolArgument", true) - .Case("DefaultIntArgument", true) - .Case("IntArgument", true) - .Case("ExprArgument", true) - .Case("UnsignedArgument", true) - .Case("VariadicUnsignedArgument", true) - .Case("VariadicExprArgument", true) - .Default(false)) + if (Args[0]->getSuperClasses().back()->getName() != "TypeArgument") continue; + // All these spellings take a single type argument. std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings"); + std::set<std::string> Emitted; + for (std::vector<Record*>::const_iterator I = Spellings.begin(), + E = Spellings.end(); I != E; ++I) { + if (Emitted.insert((*I)->getValueAsString("Name")).second) + OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", " + << "true" << ")\n"; + } + } +} + +// Emits the first-argument-is-identifier property for attributes. +void EmitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("llvm::StringSwitch code to match attributes with " + "an identifier argument", OS); + std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); + + for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); + I != E; ++I) { + Record &Attr = **I; + + // Determine whether the first argument is an identifier. + std::vector<Record *> Args = Attr.getValueAsListOfDefs("Args"); + if (Args.empty() || !isIdentifierArgument(Args[0])) + continue; + + // All these spellings take an identifier argument. + std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings"); + std::set<std::string> Emitted; for (std::vector<Record*>::const_iterator I = Spellings.begin(), E = Spellings.end(); I != E; ++I) { - OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", " - << "true" << ")\n"; + if (Emitted.insert((*I)->getValueAsString("Name")).second) + OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", " + << "true" << ")\n"; } } } @@ -1094,13 +1335,13 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) { " INHERITABLE_PARAM_ATTR(NAME)\n"; OS << "#endif\n\n"; - OS << "#ifndef MS_INHERITABLE_ATTR\n"; - OS << "#define MS_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n"; + OS << "#ifndef MS_INHERITANCE_ATTR\n"; + OS << "#define MS_INHERITANCE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n"; OS << "#endif\n\n"; - OS << "#ifndef LAST_MS_INHERITABLE_ATTR\n"; - OS << "#define LAST_MS_INHERITABLE_ATTR(NAME)" - " MS_INHERITABLE_ATTR(NAME)\n"; + OS << "#ifndef LAST_MS_INHERITANCE_ATTR\n"; + OS << "#define LAST_MS_INHERITANCE_ATTR(NAME)" + " MS_INHERITANCE_ATTR(NAME)\n"; OS << "#endif\n\n"; Record *InhClass = Records.getClass("InheritableAttr"); @@ -1124,16 +1365,16 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) { } EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs); - EmitAttrList(OS, "MS_INHERITABLE_ATTR", MSInhAttrs); + EmitAttrList(OS, "MS_INHERITANCE_ATTR", MSInhAttrs); EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs); EmitAttrList(OS, "ATTR", NonInhAttrs); OS << "#undef LAST_ATTR\n"; OS << "#undef INHERITABLE_ATTR\n"; - OS << "#undef MS_INHERITABLE_ATTR\n"; + OS << "#undef MS_INHERITANCE_ATTR\n"; OS << "#undef LAST_INHERITABLE_ATTR\n"; OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n"; - OS << "#undef LAST_MS_INHERITABLE_ATTR\n"; + OS << "#undef LAST_MS_INHERITANCE_ATTR\n"; OS << "#undef ATTR\n"; } @@ -1393,16 +1634,11 @@ void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) { << "} // end namespace clang\n"; } -// Emits the list of parsed attributes. -void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) { - emitSourceFileHeader("List of all attributes that Clang recognizes", OS); +typedef std::vector<std::pair<std::string, Record *> > ParsedAttrMap; - OS << "#ifndef PARSED_ATTR\n"; - OS << "#define PARSED_ATTR(NAME) NAME\n"; - OS << "#endif\n\n"; - +static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records) { std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"); - + ParsedAttrMap R; for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { Record &Attr = **I; @@ -1419,16 +1655,69 @@ void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) { std::string AttrName = (*I)->getValueAsString("Name"); StringRef Spelling = NormalizeAttrName(AttrName); - - OS << "PARSED_ATTR(" << Spelling << ")\n"; + R.push_back(std::make_pair(Spelling.str(), &Attr)); } } else { StringRef AttrName = Attr.getName(); AttrName = NormalizeAttrName(AttrName); - OS << "PARSED_ATTR(" << AttrName << ")\n"; + R.push_back(std::make_pair(AttrName.str(), *I)); } } } + return R; +} + +// Emits the list of parsed attributes. +void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("List of all attributes that Clang recognizes", OS); + + OS << "#ifndef PARSED_ATTR\n"; + OS << "#define PARSED_ATTR(NAME) NAME\n"; + OS << "#endif\n\n"; + + ParsedAttrMap Names = getParsedAttrList(Records); + for (ParsedAttrMap::iterator I = Names.begin(), E = Names.end(); I != E; + ++I) { + OS << "PARSED_ATTR(" << I->first << ")\n"; + } +} + +static void emitArgInfo(const Record &R, raw_ostream &OS) { + // This function will count the number of arguments specified for the + // attribute and emit the number of required arguments followed by the + // number of optional arguments. + std::vector<Record *> Args = R.getValueAsListOfDefs("Args"); + unsigned ArgCount = 0, OptCount = 0; + for (std::vector<Record *>::const_iterator I = Args.begin(), E = Args.end(); + I != E; ++I) { + const Record &Arg = **I; + Arg.getValueAsBit("Optional") ? ++OptCount : ++ArgCount; + } + OS << ArgCount << ", " << OptCount; +} + +/// Emits the parsed attribute helpers +void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Parsed attribute helpers", OS); + + ParsedAttrMap Attrs = getParsedAttrList(Records); + + OS << "static const ParsedAttrInfo AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n"; + for (ParsedAttrMap::iterator I = Attrs.begin(), E = Attrs.end(); I != E; + ++I) { + // We need to generate struct instances based off ParsedAttrInfo from + // AttributeList.cpp. + OS << " { "; + emitArgInfo(*I->second, OS); + OS << ", " << I->second->getValueAsBit("HasCustomParsing"); + OS << " }"; + + if (I + 1 != E) + OS << ","; + + OS << " // AT_" << I->first << "\n"; + } + OS << "};\n\n"; } // Emits the kind list of parsed attributes diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp index cab1c2b..857b22e 100644 --- a/contrib/llvm/tools/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp @@ -40,6 +40,7 @@ void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) { << Tag.getValueAsBit("IsReturnsCommand") << ", " << Tag.getValueAsBit("IsParamCommand") << ", " << Tag.getValueAsBit("IsTParamCommand") << ", " + << Tag.getValueAsBit("IsThrowsCommand") << ", " << Tag.getValueAsBit("IsDeprecatedCommand") << ", " << Tag.getValueAsBit("IsHeaderfileCommand") << ", " << Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", " diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp index da15c93..db159d1 100644 --- a/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -24,6 +24,7 @@ #include "llvm/Support/Debug.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" +#include "llvm/TableGen/StringToOffsetTable.h" #include "llvm/TableGen/TableGenBackend.h" #include <algorithm> #include <cctype> @@ -51,7 +52,7 @@ public: Mapping[SubGroups[j]].push_back(DiagGroups[i]); } } - + const std::vector<Record*> &getParents(const Record *Group) { return Mapping[Group]; } @@ -64,7 +65,7 @@ getCategoryFromDiagGroup(const Record *Group, // If the DiagGroup has a category, return it. std::string CatName = Group->getValueAsString("CategoryName"); if (!CatName.empty()) return CatName; - + // The diag group may the subgroup of one or more other diagnostic groups, // check these for a category as well. const std::vector<Record*> &Parents = DiagGroupParents.getParents(Group); @@ -99,32 +100,32 @@ namespace { public: DiagCategoryIDMap(RecordKeeper &records) : Records(records) { DiagGroupParentMap ParentInfo(Records); - + // The zero'th category is "". CategoryStrings.push_back(""); CategoryIDs[""] = 0; - + std::vector<Record*> Diags = Records.getAllDerivedDefinitions("Diagnostic"); for (unsigned i = 0, e = Diags.size(); i != e; ++i) { std::string Category = getDiagnosticCategory(Diags[i], ParentInfo); if (Category.empty()) continue; // Skip diags with no category. - + unsigned &ID = CategoryIDs[Category]; if (ID != 0) continue; // Already seen. - + ID = CategoryStrings.size(); CategoryStrings.push_back(Category); } } - + unsigned getID(StringRef CategoryString) { return CategoryIDs[CategoryString]; } - - typedef std::vector<std::string>::iterator iterator; - iterator begin() { return CategoryStrings.begin(); } - iterator end() { return CategoryStrings.end(); } + + typedef std::vector<std::string>::const_iterator const_iterator; + const_iterator begin() const { return CategoryStrings.begin(); } + const_iterator end() const { return CategoryStrings.end(); } }; struct GroupInfo { @@ -198,7 +199,7 @@ static void groupDiagnostics(const std::vector<Record*> &Diags, for (unsigned j = 0, e = SubGroups.size(); j != e; ++j) GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName")); } - + // Assign unique ID numbers to the groups. unsigned IDNo = 0; for (std::map<std::string, GroupInfo>::iterator @@ -505,7 +506,7 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, for (unsigned i = 0, e = Diags.size(); i != e; ++i) { const Record &R = *Diags[i]; - + // Check if this is an error that is accidentally in a warning // group. if (isError(R)) { @@ -524,11 +525,11 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, OS << "DIAG(" << R.getName() << ", "; OS << R.getValueAsDef("Class")->getName(); OS << ", diag::" << R.getValueAsDef("DefaultMapping")->getName(); - + // Description string. OS << ", \""; OS.write_escaped(R.getValueAsString("Text")) << '"'; - + // Warning associated with the diagnostic. This is stored as an index into // the alphabetically sorted warning table. if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { @@ -545,34 +546,21 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, OS << ", 0"; } - // SFINAE bit - if (R.getValueAsBit("SFINAE")) + // SFINAE response. + OS << ", " << R.getValueAsDef("SFINAE")->getName(); + + // Default warning has no Werror bit. + if (R.getValueAsBit("WarningNoWerror")) OS << ", true"; else OS << ", false"; - // Access control bit - if (R.getValueAsBit("AccessControl")) + // Default warning show in system header bit. + if (R.getValueAsBit("WarningShowInSystemHeader")) OS << ", true"; else OS << ", false"; - // FIXME: This condition is just to avoid temporary revlock, it can be - // removed. - if (R.getValue("WarningNoWerror")) { - // Default warning has no Werror bit. - if (R.getValueAsBit("WarningNoWerror")) - OS << ", true"; - else - OS << ", false"; - - // Default warning show in system header bit. - if (R.getValueAsBit("WarningShowInSystemHeader")) - OS << ", true"; - else - OS << ", false"; - } - // Category number. OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); OS << ")\n"; @@ -592,7 +580,7 @@ static std::string getDiagCategoryEnum(llvm::StringRef name) { enumName += isalnum(*I) ? *I : '_'; return enumName.str(); } - + namespace clang { void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { // Compute a mapping from a DiagGroup to all of its parents. @@ -600,7 +588,7 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { std::vector<Record*> Diags = Records.getAllDerivedDefinitions("Diagnostic"); - + std::vector<Record*> DiagGroups = Records.getAllDerivedDefinitions("DiagGroup"); @@ -619,14 +607,16 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { // that are mapped to. OS << "\n#ifdef GET_DIAG_ARRAYS\n"; unsigned MaxLen = 0; - for (std::map<std::string, GroupInfo>::iterator + OS << "static const int16_t DiagArrays[] = {\n" + << " /* Empty */ -1,\n"; + for (std::map<std::string, GroupInfo>::const_iterator I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { MaxLen = std::max(MaxLen, (unsigned)I->first.size()); const bool IsPedantic = I->first == "pedantic"; - std::vector<const Record*> &V = I->second.DiagsInGroup; + const std::vector<const Record*> &V = I->second.DiagsInGroup; if (!V.empty() || (IsPedantic && !DiagsInPedantic.empty())) { - OS << "static const short DiagArray" << I->second.IDNo << "[] = { "; + OS << " /* DiagArray" << I->second.IDNo << " */ "; for (unsigned i = 0, e = V.size(); i != e; ++i) OS << "diag::" << V[i]->getName() << ", "; // Emit the diagnostics implicitly in "pedantic". @@ -634,14 +624,22 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { for (unsigned i = 0, e = DiagsInPedantic.size(); i != e; ++i) OS << "diag::" << DiagsInPedantic[i]->getName() << ", "; } - OS << "-1 };\n"; + OS << "-1,\n"; } - + } + OS << "};\n\n"; + + OS << "static const int16_t DiagSubGroups[] = {\n" + << " /* Empty */ -1,\n"; + for (std::map<std::string, GroupInfo>::const_iterator + I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { + const bool IsPedantic = I->first == "pedantic"; + const std::vector<std::string> &SubGroups = I->second.SubGroups; if (!SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty())) { - OS << "static const short DiagSubGroup" << I->second.IDNo << "[] = { "; + OS << " /* DiagSubGroup" << I->second.IDNo << " */ "; for (unsigned i = 0, e = SubGroups.size(); i != e; ++i) { - std::map<std::string, GroupInfo>::iterator RI = + std::map<std::string, GroupInfo>::const_iterator RI = DiagsInGroup.find(SubGroups[i]); assert(RI != DiagsInGroup.end() && "Referenced without existing?"); OS << RI->second.IDNo << ", "; @@ -651,60 +649,86 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) { for (unsigned i = 0, e = GroupsInPedantic.size(); i != e; ++i) { const std::string &GroupName = GroupsInPedantic[i]->getValueAsString("GroupName"); - std::map<std::string, GroupInfo>::iterator RI = + std::map<std::string, GroupInfo>::const_iterator RI = DiagsInGroup.find(GroupName); assert(RI != DiagsInGroup.end() && "Referenced without existing?"); OS << RI->second.IDNo << ", "; } } - OS << "-1 };\n"; + OS << "-1,\n"; } } + OS << "};\n\n"; + + StringToOffsetTable GroupNames; + for (std::map<std::string, GroupInfo>::const_iterator + I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { + // Store a pascal-style length byte at the beginning of the string. + std::string Name = char(I->first.size()) + I->first; + GroupNames.GetOrAddStringOffset(Name, false); + } + + OS << "static const char DiagGroupNames[] = {\n"; + GroupNames.EmitString(OS); + OS << "};\n\n"; + OS << "#endif // GET_DIAG_ARRAYS\n\n"; - + // Emit the table now. OS << "\n#ifdef GET_DIAG_TABLE\n"; - for (std::map<std::string, GroupInfo>::iterator + unsigned SubGroupIndex = 1, DiagArrayIndex = 1; + for (std::map<std::string, GroupInfo>::const_iterator I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I) { // Group option string. - OS << " { "; - OS << I->first.size() << ", "; - OS << "\""; + OS << " { /* "; if (I->first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789!@#$%^*-+=:?")!=std::string::npos) PrintFatalError("Invalid character in diagnostic group '" + I->first + "'"); - OS.write_escaped(I->first) << "\"," - << std::string(MaxLen-I->first.size()+1, ' '); + OS << I->first << " */ " << std::string(MaxLen-I->first.size(), ' '); + // Store a pascal-style length byte at the beginning of the string. + std::string Name = char(I->first.size()) + I->first; + OS << GroupNames.GetOrAddStringOffset(Name, false) << ", "; // Special handling for 'pedantic'. const bool IsPedantic = I->first == "pedantic"; // Diagnostics in the group. - const bool hasDiags = !I->second.DiagsInGroup.empty() || + const std::vector<const Record*> &V = I->second.DiagsInGroup; + const bool hasDiags = !V.empty() || (IsPedantic && !DiagsInPedantic.empty()); - if (!hasDiags) - OS << "0, "; - else - OS << "DiagArray" << I->second.IDNo << ", "; - + if (hasDiags) { + OS << "/* DiagArray" << I->second.IDNo << " */ " + << DiagArrayIndex << ", "; + if (IsPedantic) + DiagArrayIndex += DiagsInPedantic.size(); + DiagArrayIndex += V.size() + 1; + } else { + OS << "/* Empty */ 0, "; + } + // Subgroups. - const bool hasSubGroups = !I->second.SubGroups.empty() || + const std::vector<std::string> &SubGroups = I->second.SubGroups; + const bool hasSubGroups = !SubGroups.empty() || (IsPedantic && !GroupsInPedantic.empty()); - if (!hasSubGroups) - OS << 0; - else - OS << "DiagSubGroup" << I->second.IDNo; + if (hasSubGroups) { + OS << "/* DiagSubGroup" << I->second.IDNo << " */ " << SubGroupIndex; + if (IsPedantic) + SubGroupIndex += GroupsInPedantic.size(); + SubGroupIndex += SubGroups.size() + 1; + } else { + OS << "/* Empty */ 0"; + } OS << " },\n"; } OS << "#endif // GET_DIAG_TABLE\n\n"; - + // Emit the category table next. DiagCategoryIDMap CategoriesByID(Records); OS << "\n#ifdef GET_CATEGORY_TABLE\n"; - for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(), + for (DiagCategoryIDMap::const_iterator I = CategoriesByID.begin(), E = CategoriesByID.end(); I != E; ++I) OS << "CATEGORY(\"" << *I << "\", " << getDiagCategoryEnum(*I) << ")\n"; OS << "#endif // GET_CATEGORY_TABLE\n\n"; @@ -721,18 +745,18 @@ struct RecordIndexElement RecordIndexElement() {} explicit RecordIndexElement(Record const &R): Name(R.getName()) {} - + std::string Name; }; struct RecordIndexElementSorter : public std::binary_function<RecordIndexElement, RecordIndexElement, bool> { - + bool operator()(RecordIndexElement const &Lhs, RecordIndexElement const &Rhs) const { return Lhs.Name < Rhs.Name; } - + }; } // end anonymous namespace. @@ -741,19 +765,19 @@ namespace clang { void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) { const std::vector<Record*> &Diags = Records.getAllDerivedDefinitions("Diagnostic"); - + std::vector<RecordIndexElement> Index; Index.reserve(Diags.size()); for (unsigned i = 0, e = Diags.size(); i != e; ++i) { - const Record &R = *(Diags[i]); + const Record &R = *(Diags[i]); Index.push_back(RecordIndexElement(R)); } - + std::sort(Index.begin(), Index.end(), RecordIndexElementSorter()); - + for (unsigned i = 0, e = Index.size(); i != e; ++i) { const RecordIndexElement &R = Index[i]; - + OS << "DIAG_NAME_INDEX(" << R.Name << ")\n"; } } diff --git a/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp index 34b955e..b0939c9 100644 --- a/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp +++ b/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp @@ -40,31 +40,58 @@ enum OpKind { OpUnavailable, OpAdd, OpAddl, + OpAddlHi, OpAddw, + OpAddwHi, OpSub, OpSubl, + OpSublHi, OpSubw, + OpSubwHi, OpMul, OpMla, OpMlal, + OpMullHi, + OpMullHiN, + OpMlalHi, + OpMlalHiN, OpMls, OpMlsl, + OpMlslHi, + OpMlslHiN, OpMulN, OpMlaN, OpMlsN, + OpFMlaN, + OpFMlsN, OpMlalN, OpMlslN, OpMulLane, + OpMulXLane, OpMullLane, + OpMullHiLane, OpMlaLane, OpMlsLane, OpMlalLane, + OpMlalHiLane, OpMlslLane, + OpMlslHiLane, OpQDMullLane, + OpQDMullHiLane, OpQDMlalLane, + OpQDMlalHiLane, OpQDMlslLane, + OpQDMlslHiLane, OpQDMulhLane, OpQRDMulhLane, + OpFMSLane, + OpFMSLaneQ, + OpTrn1, + OpZip1, + OpUzp1, + OpTrn2, + OpZip2, + OpUzp2, OpEq, OpGe, OpLe, @@ -87,10 +114,49 @@ enum OpKind { OpRev16, OpRev32, OpRev64, + OpXtnHi, + OpSqxtunHi, + OpQxtnHi, + OpFcvtnHi, + OpFcvtlHi, + OpFcvtxnHi, OpReinterpret, + OpAddhnHi, + OpRAddhnHi, + OpSubhnHi, + OpRSubhnHi, OpAbdl, + OpAbdlHi, OpAba, - OpAbal + OpAbal, + OpAbalHi, + OpQDMullHi, + OpQDMullHiN, + OpQDMlalHi, + OpQDMlalHiN, + OpQDMlslHi, + OpQDMlslHiN, + OpDiv, + OpLongHi, + OpNarrowHi, + OpMovlHi, + OpCopyLane, + OpCopyQLane, + OpCopyLaneQ, + OpScalarMulLane, + OpScalarMulLaneQ, + OpScalarMulXLane, + OpScalarMulXLaneQ, + OpScalarVMulXLane, + OpScalarVMulXLaneQ, + OpScalarQDMullLane, + OpScalarQDMullLaneQ, + OpScalarQDMulHiLane, + OpScalarQDMulHiLaneQ, + OpScalarQRDMulHiLane, + OpScalarQRDMulHiLaneQ, + OpScalarGetLane, + OpScalarSetLane }; enum ClassKind { @@ -126,8 +192,10 @@ public: Int64, Poly8, Poly16, + Poly64, Float16, - Float32 + Float32, + Float64 }; NeonTypeFlags(unsigned F) : Flags(F) {} @@ -154,31 +222,58 @@ public: OpMap["OP_UNAVAILABLE"] = OpUnavailable; OpMap["OP_ADD"] = OpAdd; OpMap["OP_ADDL"] = OpAddl; + OpMap["OP_ADDLHi"] = OpAddlHi; OpMap["OP_ADDW"] = OpAddw; + OpMap["OP_ADDWHi"] = OpAddwHi; OpMap["OP_SUB"] = OpSub; OpMap["OP_SUBL"] = OpSubl; + OpMap["OP_SUBLHi"] = OpSublHi; OpMap["OP_SUBW"] = OpSubw; + OpMap["OP_SUBWHi"] = OpSubwHi; OpMap["OP_MUL"] = OpMul; OpMap["OP_MLA"] = OpMla; OpMap["OP_MLAL"] = OpMlal; + OpMap["OP_MULLHi"] = OpMullHi; + OpMap["OP_MULLHi_N"] = OpMullHiN; + OpMap["OP_MLALHi"] = OpMlalHi; + OpMap["OP_MLALHi_N"] = OpMlalHiN; OpMap["OP_MLS"] = OpMls; OpMap["OP_MLSL"] = OpMlsl; + OpMap["OP_MLSLHi"] = OpMlslHi; + OpMap["OP_MLSLHi_N"] = OpMlslHiN; OpMap["OP_MUL_N"] = OpMulN; OpMap["OP_MLA_N"] = OpMlaN; OpMap["OP_MLS_N"] = OpMlsN; + OpMap["OP_FMLA_N"] = OpFMlaN; + OpMap["OP_FMLS_N"] = OpFMlsN; OpMap["OP_MLAL_N"] = OpMlalN; OpMap["OP_MLSL_N"] = OpMlslN; OpMap["OP_MUL_LN"]= OpMulLane; + OpMap["OP_MULX_LN"]= OpMulXLane; OpMap["OP_MULL_LN"] = OpMullLane; + OpMap["OP_MULLHi_LN"] = OpMullHiLane; OpMap["OP_MLA_LN"]= OpMlaLane; OpMap["OP_MLS_LN"]= OpMlsLane; OpMap["OP_MLAL_LN"] = OpMlalLane; + OpMap["OP_MLALHi_LN"] = OpMlalHiLane; OpMap["OP_MLSL_LN"] = OpMlslLane; + OpMap["OP_MLSLHi_LN"] = OpMlslHiLane; OpMap["OP_QDMULL_LN"] = OpQDMullLane; + OpMap["OP_QDMULLHi_LN"] = OpQDMullHiLane; OpMap["OP_QDMLAL_LN"] = OpQDMlalLane; + OpMap["OP_QDMLALHi_LN"] = OpQDMlalHiLane; OpMap["OP_QDMLSL_LN"] = OpQDMlslLane; + OpMap["OP_QDMLSLHi_LN"] = OpQDMlslHiLane; OpMap["OP_QDMULH_LN"] = OpQDMulhLane; OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane; + OpMap["OP_FMS_LN"] = OpFMSLane; + OpMap["OP_FMS_LNQ"] = OpFMSLaneQ; + OpMap["OP_TRN1"] = OpTrn1; + OpMap["OP_ZIP1"] = OpZip1; + OpMap["OP_UZP1"] = OpUzp1; + OpMap["OP_TRN2"] = OpTrn2; + OpMap["OP_ZIP2"] = OpZip2; + OpMap["OP_UZP2"] = OpUzp2; OpMap["OP_EQ"] = OpEq; OpMap["OP_GE"] = OpGe; OpMap["OP_LE"] = OpLe; @@ -201,10 +296,49 @@ public: OpMap["OP_REV16"] = OpRev16; OpMap["OP_REV32"] = OpRev32; OpMap["OP_REV64"] = OpRev64; + OpMap["OP_XTN"] = OpXtnHi; + OpMap["OP_SQXTUN"] = OpSqxtunHi; + OpMap["OP_QXTN"] = OpQxtnHi; + OpMap["OP_VCVT_NA_HI"] = OpFcvtnHi; + OpMap["OP_VCVT_EX_HI"] = OpFcvtlHi; + OpMap["OP_VCVTX_HI"] = OpFcvtxnHi; OpMap["OP_REINT"] = OpReinterpret; + OpMap["OP_ADDHNHi"] = OpAddhnHi; + OpMap["OP_RADDHNHi"] = OpRAddhnHi; + OpMap["OP_SUBHNHi"] = OpSubhnHi; + OpMap["OP_RSUBHNHi"] = OpRSubhnHi; OpMap["OP_ABDL"] = OpAbdl; + OpMap["OP_ABDLHi"] = OpAbdlHi; OpMap["OP_ABA"] = OpAba; OpMap["OP_ABAL"] = OpAbal; + OpMap["OP_ABALHi"] = OpAbalHi; + OpMap["OP_QDMULLHi"] = OpQDMullHi; + OpMap["OP_QDMULLHi_N"] = OpQDMullHiN; + OpMap["OP_QDMLALHi"] = OpQDMlalHi; + OpMap["OP_QDMLALHi_N"] = OpQDMlalHiN; + OpMap["OP_QDMLSLHi"] = OpQDMlslHi; + OpMap["OP_QDMLSLHi_N"] = OpQDMlslHiN; + OpMap["OP_DIV"] = OpDiv; + OpMap["OP_LONG_HI"] = OpLongHi; + OpMap["OP_NARROW_HI"] = OpNarrowHi; + OpMap["OP_MOVL_HI"] = OpMovlHi; + OpMap["OP_COPY_LN"] = OpCopyLane; + OpMap["OP_COPYQ_LN"] = OpCopyQLane; + OpMap["OP_COPY_LNQ"] = OpCopyLaneQ; + OpMap["OP_SCALAR_MUL_LN"]= OpScalarMulLane; + OpMap["OP_SCALAR_MUL_LNQ"]= OpScalarMulLaneQ; + OpMap["OP_SCALAR_MULX_LN"]= OpScalarMulXLane; + OpMap["OP_SCALAR_MULX_LNQ"]= OpScalarMulXLaneQ; + OpMap["OP_SCALAR_VMULX_LN"]= OpScalarVMulXLane; + OpMap["OP_SCALAR_VMULX_LNQ"]= OpScalarVMulXLaneQ; + OpMap["OP_SCALAR_QDMULL_LN"] = OpScalarQDMullLane; + OpMap["OP_SCALAR_QDMULL_LNQ"] = OpScalarQDMullLaneQ; + OpMap["OP_SCALAR_QDMULH_LN"] = OpScalarQDMulHiLane; + OpMap["OP_SCALAR_QDMULH_LNQ"] = OpScalarQDMulHiLaneQ; + OpMap["OP_SCALAR_QRDMULH_LN"] = OpScalarQRDMulHiLane; + OpMap["OP_SCALAR_QRDMULH_LNQ"] = OpScalarQRDMulHiLaneQ; + OpMap["OP_SCALAR_GET_LN"] = OpScalarGetLane; + OpMap["OP_SCALAR_SET_LN"] = OpScalarSetLane; Record *SI = R.getClass("SInst"); Record *II = R.getClass("IInst"); @@ -235,7 +369,18 @@ public: void runTests(raw_ostream &o); private: - void emitIntrinsic(raw_ostream &OS, Record *R); + void emitIntrinsic(raw_ostream &OS, Record *R, + StringMap<ClassKind> &EmittedMap); + void genBuiltinsDef(raw_ostream &OS, StringMap<ClassKind> &A64IntrinsicMap, + bool isA64GenBuiltinDef); + void genOverloadTypeCheckCode(raw_ostream &OS, + StringMap<ClassKind> &A64IntrinsicMap, + bool isA64TypeCheck); + void genIntrinsicRangeCheckCode(raw_ostream &OS, + StringMap<ClassKind> &A64IntrinsicMap, + bool isA64RangeCheck); + void genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap, + bool isA64TestGen); }; } // end anonymous namespace @@ -249,7 +394,8 @@ static void ParseTypes(Record *r, std::string &s, int len = 0; for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) { - if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U') + if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U' + || data[len] == 'H' || data[len] == 'S') continue; switch (data[len]) { @@ -259,6 +405,7 @@ static void ParseTypes(Record *r, std::string &s, case 'l': case 'h': case 'f': + case 'd': break; default: PrintFatalError(r->getLoc(), @@ -282,6 +429,8 @@ static char Widen(const char t) { return 'l'; case 'h': return 'f'; + case 'f': + return 'd'; default: PrintFatalError("unhandled type in widen!"); } @@ -299,18 +448,46 @@ static char Narrow(const char t) { return 'i'; case 'f': return 'h'; + case 'd': + return 'f'; default: PrintFatalError("unhandled type in narrow!"); } } +static std::string GetNarrowTypestr(StringRef ty) +{ + std::string s; + for (size_t i = 0, end = ty.size(); i < end; i++) { + switch (ty[i]) { + case 's': + s += 'c'; + break; + case 'i': + s += 's'; + break; + case 'l': + s += 'i'; + break; + default: + s += ty[i]; + break; + } + } + + return s; +} + /// For a particular StringRef, return the base type code, and whether it has /// the quad-vector, polynomial, or unsigned modifiers set. static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) { unsigned off = 0; - + // ignore scalar. + if (ty[off] == 'S') { + ++off; + } // remember quad. - if (ty[off] == 'Q') { + if (ty[off] == 'Q' || ty[off] == 'H') { quad = true; ++off; } @@ -342,27 +519,52 @@ static char ModType(const char mod, char type, bool &quad, bool &poly, usgn = true; } break; + case 'b': + scal = true; case 'u': usgn = true; poly = false; if (type == 'f') type = 'i'; + if (type == 'd') + type = 'l'; break; + case '$': + scal = true; case 'x': usgn = false; poly = false; if (type == 'f') type = 'i'; + if (type == 'd') + type = 'l'; break; + case 'o': + scal = true; + type = 'd'; + usgn = false; + break; + case 'y': + scal = true; case 'f': if (type == 'h') quad = true; type = 'f'; usgn = false; break; + case 'F': + type = 'd'; + usgn = false; + break; case 'g': quad = false; break; + case 'B': + case 'C': + case 'D': + case 'j': + quad = true; + break; case 'w': type = Widen(type); quad = true; @@ -379,6 +581,14 @@ static char ModType(const char mod, char type, bool &quad, bool &poly, scal = true; usgn = true; break; + case 'z': + type = Narrow(type); + scal = true; + break; + case 'r': + type = Widen(type); + scal = true; + break; case 's': case 'a': scal = true; @@ -397,16 +607,28 @@ static char ModType(const char mod, char type, bool &quad, bool &poly, if (type == 'h') quad = false; break; + case 'q': + type = Narrow(type); + quad = true; + break; case 'e': type = Narrow(type); usgn = true; break; + case 'm': + type = Narrow(type); + quad = false; + break; default: break; } return type; } +static bool IsMultiVecProto(const char p) { + return ((p >= '2' && p <= '4') || (p >= 'B' && p <= 'D')); +} + /// TypeString - for a modifier and type, generate the name of the typedef for /// that type. QUc -> uint8x8_t. static std::string TypeString(const char mod, StringRef typestr) { @@ -453,7 +675,7 @@ static std::string TypeString(const char mod, StringRef typestr) { s += quad ? "x4" : "x2"; break; case 'l': - s += "int64"; + s += (poly && !usgn)? "poly64" : "int64"; if (scal) break; s += quad ? "x2" : "x1"; @@ -470,15 +692,22 @@ static std::string TypeString(const char mod, StringRef typestr) { break; s += quad ? "x4" : "x2"; break; + case 'd': + s += "float64"; + if (scal) + break; + s += quad ? "x2" : "x1"; + break; + default: PrintFatalError("unhandled type!"); } - if (mod == '2') + if (mod == '2' || mod == 'B') s += "x2"; - if (mod == '3') + if (mod == '3' || mod == 'C') s += "x3"; - if (mod == '4') + if (mod == '4' || mod == 'D') s += "x4"; // Append _t, finishing the type string typedef type. @@ -527,7 +756,8 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr, type = 's'; usgn = true; } - usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f'); + usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && + scal && type != 'f' && type != 'd'); if (scal) { SmallString<128> s; @@ -554,10 +784,12 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr, // returning structs of 2, 3, or 4 vectors which are returned in a sret-like // fashion, storing them to a pointer arg. if (ret) { - if (mod >= '2' && mod <= '4') + if (IsMultiVecProto(mod)) return "vv*"; // void result with void* first argument if (mod == 'f' || (ck != ClassB && type == 'f')) return quad ? "V4f" : "V2f"; + if (mod == 'F' || (ck != ClassB && type == 'd')) + return quad ? "V2d" : "V1d"; if (ck != ClassB && type == 's') return quad ? "V8s" : "V4s"; if (ck != ClassB && type == 'i') @@ -569,15 +801,17 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr, } // Non-return array types are passed as individual vectors. - if (mod == '2') + if (mod == '2' || mod == 'B') return quad ? "V16ScV16Sc" : "V8ScV8Sc"; - if (mod == '3') + if (mod == '3' || mod == 'C') return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc"; - if (mod == '4') + if (mod == '4' || mod == 'D') return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc"; if (mod == 'f' || (ck != ClassB && type == 'f')) return quad ? "V4f" : "V2f"; + if (mod == 'F' || (ck != ClassB && type == 'd')) + return quad ? "V2d" : "V1d"; if (ck != ClassB && type == 's') return quad ? "V8s" : "V4s"; if (ck != ClassB && type == 'i') @@ -625,7 +859,7 @@ static void InstructionTypeCode(const StringRef &typeStr, break; case 'l': switch (ck) { - case ClassS: typeCode = usgn ? "u64" : "s64"; break; + case ClassS: typeCode = poly ? "p64" : usgn ? "u64" : "s64"; break; case ClassI: typeCode = "i64"; break; case ClassW: typeCode = "64"; break; default: break; @@ -647,17 +881,60 @@ static void InstructionTypeCode(const StringRef &typeStr, default: break; } break; + case 'd': + switch (ck) { + case ClassS: + case ClassI: + typeCode += "f64"; + break; + case ClassW: + PrintFatalError("unhandled type!"); + default: + break; + } + break; default: PrintFatalError("unhandled type!"); } } +static char Insert_BHSD_Suffix(StringRef typestr){ + unsigned off = 0; + if(typestr[off++] == 'S'){ + while(typestr[off] == 'Q' || typestr[off] == 'H'|| + typestr[off] == 'P' || typestr[off] == 'U') + ++off; + switch (typestr[off]){ + default : break; + case 'c' : return 'b'; + case 's' : return 'h'; + case 'i' : + case 'f' : return 's'; + case 'l' : + case 'd' : return 'd'; + } + } + return 0; +} + +static bool endsWith_xN(std::string const &name) { + if (name.length() > 3) { + if (name.compare(name.length() - 3, 3, "_x2") == 0 || + name.compare(name.length() - 3, 3, "_x3") == 0 || + name.compare(name.length() - 3, 3, "_x4") == 0) + return true; + } + return false; +} + /// MangleName - Append a type or width suffix to a base neon function name, -/// and insert a 'q' in the appropriate location if the operation works on -/// 128b rather than 64b. E.g. turn "vst2_lane" into "vst2q_lane_f32", etc. +/// and insert a 'q' in the appropriate location if type string starts with 'Q'. +/// E.g. turn "vst2_lane" into "vst2q_lane_f32", etc. +/// Insert proper 'b' 'h' 's' 'd' if prefix 'S' is used. static std::string MangleName(const std::string &name, StringRef typestr, ClassKind ck) { - if (name == "vcvt_f32_f16") + if (name == "vcvt_f32_f16" || name == "vcvt_f32_f64" || + name == "vcvt_f64_f32") return name; bool quad = false; @@ -668,7 +945,11 @@ static std::string MangleName(const std::string &name, StringRef typestr, std::string s = name; if (typeCode.size() > 0) { - s += "_" + typeCode; + // If the name is end with _xN (N = 2,3,4), insert the typeCode before _xN. + if (endsWith_xN(s)) + s.insert(s.length() - 3, "_" + typeCode); + else + s += "_" + typeCode; } if (ck == ClassB) @@ -676,9 +957,14 @@ static std::string MangleName(const std::string &name, StringRef typestr, // Insert a 'q' before the first '_' character so that it ends up before // _lane or _n on vector-scalar operations. - if (quad) { + if (typestr.find("Q") != StringRef::npos) { + size_t pos = s.find('_'); + s = s.insert(pos, "q"); + } + char ins = Insert_BHSD_Suffix(typestr); + if(ins){ size_t pos = s.find('_'); - s = s.insert(pos, "q"); + s = s.insert(pos, &ins, 1); } return s; @@ -770,9 +1056,7 @@ GenerateRegisterCheckPatternForLoadStores(const StringRef &NameRef, // a dup/lane instruction. if (IsLDSTOne) { if ((HasLanePostfix || HasDupPostfix) && OutTypeCode != "8") { - RegisterSuffix += ", :" + OutTypeCode; - } else if (OutTypeCode == "64") { - RegisterSuffix += ", :64"; + RegisterSuffix += ":" + OutTypeCode; } } @@ -828,6 +1112,7 @@ static void NormalizeProtoForRegisterPatternCreation(const std::string &Name, switch (Proto[i]) { case 'u': case 'f': + case 'F': case 'd': case 's': case 'x': @@ -840,6 +1125,7 @@ static void NormalizeProtoForRegisterPatternCreation(const std::string &Name, NormedProto += 'q'; break; case 'g': + case 'j': case 'h': case 'e': NormedProto += 'd'; @@ -1158,7 +1444,8 @@ static bool MacroArgUsedDirectly(const std::string &proto, unsigned i) { } // Generate the string "(argtype a, argtype b, ...)" -static std::string GenArgs(const std::string &proto, StringRef typestr) { +static std::string GenArgs(const std::string &proto, StringRef typestr, + const std::string &name) { bool define = UseMacro(proto); char arg = 'a'; @@ -1176,6 +1463,9 @@ static std::string GenArgs(const std::string &proto, StringRef typestr) { s += TypeString(proto[i], typestr) + " __"; } s.push_back(arg); + //To avoid argument being multiple defined, add extra number for renaming. + if (name == "vcopy_lane" || name == "vcopy_laneq") + s.push_back('1'); if ((i + 1) < e) s += ", "; } @@ -1186,7 +1476,8 @@ static std::string GenArgs(const std::string &proto, StringRef typestr) { // Macro arguments are not type-checked like inline function arguments, so // assign them to local temporaries to get the right type checking. -static std::string GenMacroLocals(const std::string &proto, StringRef typestr) { +static std::string GenMacroLocals(const std::string &proto, StringRef typestr, + const std::string &name ) { char arg = 'a'; std::string s; bool generatedLocal = false; @@ -1197,11 +1488,18 @@ static std::string GenMacroLocals(const std::string &proto, StringRef typestr) { if (MacroArgUsedDirectly(proto, i)) continue; generatedLocal = true; + bool extranumber = false; + if (name == "vcopy_lane" || name == "vcopy_laneq") + extranumber = true; s += TypeString(proto[i], typestr) + " __"; s.push_back(arg); + if(extranumber) + s.push_back('1'); s += " = ("; s.push_back(arg); + if(extranumber) + s.push_back('1'); s += "); "; } @@ -1211,13 +1509,60 @@ static std::string GenMacroLocals(const std::string &proto, StringRef typestr) { } // Use the vmovl builtin to sign-extend or zero-extend a vector. -static std::string Extend(StringRef typestr, const std::string &a) { +static std::string Extend(StringRef typestr, const std::string &a, bool h=0) { + std::string s, high; + high = h ? "_high" : ""; + s = MangleName("vmovl" + high, typestr, ClassS); + s += "(" + a + ")"; + return s; +} + +// Get the high 64-bit part of a vector +static std::string GetHigh(const std::string &a, StringRef typestr) { std::string s; - s = MangleName("vmovl", typestr, ClassS); + s = MangleName("vget_high", typestr, ClassS); s += "(" + a + ")"; return s; } +// Gen operation with two operands and get high 64-bit for both of two operands. +static std::string Gen2OpWith2High(StringRef typestr, + const std::string &op, + const std::string &a, + const std::string &b) { + std::string s; + std::string Op1 = GetHigh(a, typestr); + std::string Op2 = GetHigh(b, typestr); + s = MangleName(op, typestr, ClassS); + s += "(" + Op1 + ", " + Op2 + ");"; + return s; +} + +// Gen operation with three operands and get high 64-bit of the latter +// two operands. +static std::string Gen3OpWith2High(StringRef typestr, + const std::string &op, + const std::string &a, + const std::string &b, + const std::string &c) { + std::string s; + std::string Op1 = GetHigh(b, typestr); + std::string Op2 = GetHigh(c, typestr); + s = MangleName(op, typestr, ClassS); + s += "(" + a + ", " + Op1 + ", " + Op2 + ");"; + return s; +} + +// Gen combine operation by putting a on low 64-bit, and b on high 64-bit. +static std::string GenCombine(std::string typestr, + const std::string &a, + const std::string &b) { + std::string s; + s = MangleName("vcombine", typestr, ClassS); + s += "(" + a + ", " + b + ")"; + return s; +} + static std::string Duplicate(unsigned nElts, StringRef typestr, const std::string &a) { std::string s; @@ -1242,6 +1587,15 @@ static std::string SplatLane(unsigned nElts, const std::string &vec, return s; } +static std::string RemoveHigh(const std::string &name) { + std::string s = name; + std::size_t found = s.find("_high_"); + if (found == std::string::npos) + PrintFatalError("name should contain \"_high_\" for high intrinsics"); + s.replace(found, 5, ""); + return s; +} + static unsigned GetNumElements(StringRef typestr, bool &quad) { quad = false; bool dummy = false; @@ -1254,6 +1608,9 @@ static unsigned GetNumElements(StringRef typestr, bool &quad) { case 'l': nElts = 1; break; case 'h': nElts = 4; break; case 'f': nElts = 2; break; + case 'd': + nElts = 1; + break; default: PrintFatalError("unhandled type!"); } @@ -1262,8 +1619,8 @@ static unsigned GetNumElements(StringRef typestr, bool &quad) { } // Generate the definition for this intrinsic, e.g. "a + b" for OpAdd. -static std::string GenOpString(OpKind op, const std::string &proto, - StringRef typestr) { +static std::string GenOpString(const std::string &name, OpKind op, + const std::string &proto, StringRef typestr) { bool quad; unsigned nElts = GetNumElements(typestr, quad); bool define = UseMacro(proto); @@ -1281,31 +1638,59 @@ static std::string GenOpString(OpKind op, const std::string &proto, case OpAddl: s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";"; break; + case OpAddlHi: + s += Extend(typestr, "__a", 1) + " + " + Extend(typestr, "__b", 1) + ";"; + break; case OpAddw: s += "__a + " + Extend(typestr, "__b") + ";"; break; + case OpAddwHi: + s += "__a + " + Extend(typestr, "__b", 1) + ";"; + break; case OpSub: s += "__a - __b;"; break; case OpSubl: s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";"; break; + case OpSublHi: + s += Extend(typestr, "__a", 1) + " - " + Extend(typestr, "__b", 1) + ";"; + break; case OpSubw: s += "__a - " + Extend(typestr, "__b") + ";"; break; + case OpSubwHi: + s += "__a - " + Extend(typestr, "__b", 1) + ";"; + break; case OpMulN: s += "__a * " + Duplicate(nElts, typestr, "__b") + ";"; break; case OpMulLane: s += "__a * " + SplatLane(nElts, "__b", "__c") + ";"; break; + case OpMulXLane: + s += MangleName("vmulx", typestr, ClassS) + "(__a, " + + SplatLane(nElts, "__b", "__c") + ");"; + break; case OpMul: s += "__a * __b;"; break; + case OpFMlaN: + s += MangleName("vfma", typestr, ClassS); + s += "(__a, __b, " + Duplicate(nElts,typestr, "__c") + ");"; + break; + case OpFMlsN: + s += MangleName("vfms", typestr, ClassS); + s += "(__a, __b, " + Duplicate(nElts,typestr, "__c") + ");"; + break; case OpMullLane: s += MangleName("vmull", typestr, ClassS) + "(__a, " + SplatLane(nElts, "__b", "__c") + ");"; break; + case OpMullHiLane: + s += MangleName("vmull", typestr, ClassS) + "(" + + GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");"; + break; case OpMlaN: s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");"; break; @@ -1323,15 +1708,45 @@ static std::string GenOpString(OpKind op, const std::string &proto, s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " + SplatLane(nElts, "__c", "__d") + ");"; break; + case OpMlalHiLane: + s += "__a + " + MangleName("vmull", typestr, ClassS) + "(" + + GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");"; + break; case OpMlal: s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);"; break; + case OpMullHi: + s += Gen2OpWith2High(typestr, "vmull", "__a", "__b"); + break; + case OpMullHiN: + s += MangleName("vmull_n", typestr, ClassS); + s += "(" + GetHigh("__a", typestr) + ", __b);"; + return s; + case OpMlalHi: + s += Gen3OpWith2High(typestr, "vmlal", "__a", "__b", "__c"); + break; + case OpMlalHiN: + s += MangleName("vmlal_n", typestr, ClassS); + s += "(__a, " + GetHigh("__b", typestr) + ", __c);"; + return s; case OpMlsN: s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");"; break; case OpMlsLane: s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");"; break; + case OpFMSLane: + s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; + s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; + s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n "; + s += MangleName("vfma_lane", typestr, ClassS) + "(__a1, __b1, -__c1, __d);"; + break; + case OpFMSLaneQ: + s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; + s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; + s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n "; + s += MangleName("vfma_laneq", typestr, ClassS) + "(__a1, __b1, -__c1, __d);"; + break; case OpMls: s += "__a - (__b * __c);"; break; @@ -1343,21 +1758,44 @@ static std::string GenOpString(OpKind op, const std::string &proto, s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " + SplatLane(nElts, "__c", "__d") + ");"; break; + case OpMlslHiLane: + s += "__a - " + MangleName("vmull", typestr, ClassS) + "(" + + GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");"; + break; case OpMlsl: s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);"; break; + case OpMlslHi: + s += Gen3OpWith2High(typestr, "vmlsl", "__a", "__b", "__c"); + break; + case OpMlslHiN: + s += MangleName("vmlsl_n", typestr, ClassS); + s += "(__a, " + GetHigh("__b", typestr) + ", __c);"; + break; case OpQDMullLane: s += MangleName("vqdmull", typestr, ClassS) + "(__a, " + SplatLane(nElts, "__b", "__c") + ");"; break; + case OpQDMullHiLane: + s += MangleName("vqdmull", typestr, ClassS) + "(" + + GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");"; + break; case OpQDMlalLane: s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " + SplatLane(nElts, "__c", "__d") + ");"; break; + case OpQDMlalHiLane: + s += MangleName("vqdmlal", typestr, ClassS) + "(__a, " + + GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");"; + break; case OpQDMlslLane: s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " + SplatLane(nElts, "__c", "__d") + ");"; break; + case OpQDMlslHiLane: + s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, " + + GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");"; + break; case OpQDMulhLane: s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " + SplatLane(nElts, "__b", "__c") + ");"; @@ -1410,12 +1848,17 @@ static std::string GenOpString(OpKind op, const std::string &proto, s += ", (int64x1_t)__b, 0, 1);"; break; case OpHi: - s += "(" + ts + - ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 1);"; + // nElts is for the result vector, so the source is twice that number. + s += "__builtin_shufflevector(__a, __a"; + for (unsigned i = nElts; i < nElts * 2; ++i) + s += ", " + utostr(i); + s+= ");"; break; case OpLo: - s += "(" + ts + - ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 0);"; + s += "__builtin_shufflevector(__a, __a"; + for (unsigned i = 0; i < nElts; ++i) + s += ", " + utostr(i); + s+= ");"; break; case OpDup: s += Duplicate(nElts, typestr, "__a") + ";"; @@ -1455,6 +1898,94 @@ static std::string GenOpString(OpKind op, const std::string &proto, s += ");"; break; } + case OpXtnHi: { + s = TypeString(proto[1], typestr) + " __a1 = " + + MangleName("vmovn", typestr, ClassS) + "(__b);\n " + + "return __builtin_shufflevector(__a, __a1"; + for (unsigned i = 0; i < nElts * 4; ++i) + s += ", " + utostr(i); + s += ");"; + break; + } + case OpSqxtunHi: { + s = TypeString(proto[1], typestr) + " __a1 = " + + MangleName("vqmovun", typestr, ClassS) + "(__b);\n " + + "return __builtin_shufflevector(__a, __a1"; + for (unsigned i = 0; i < nElts * 4; ++i) + s += ", " + utostr(i); + s += ");"; + break; + } + case OpQxtnHi: { + s = TypeString(proto[1], typestr) + " __a1 = " + + MangleName("vqmovn", typestr, ClassS) + "(__b);\n " + + "return __builtin_shufflevector(__a, __a1"; + for (unsigned i = 0; i < nElts * 4; ++i) + s += ", " + utostr(i); + s += ");"; + break; + } + case OpFcvtnHi: { + std::string FName = (nElts == 1) ? "vcvt_f32" : "vcvt_f16"; + s = TypeString(proto[1], typestr) + " __a1 = " + + MangleName(FName, typestr, ClassS) + "(__b);\n " + + "return __builtin_shufflevector(__a, __a1"; + for (unsigned i = 0; i < nElts * 4; ++i) + s += ", " + utostr(i); + s += ");"; + break; + } + case OpFcvtlHi: { + std::string FName = (nElts == 2) ? "vcvt_f64" : "vcvt_f32"; + s = TypeString('d', typestr) + " __a1 = " + GetHigh("__a", typestr) + + ";\n return " + MangleName(FName, typestr, ClassS) + "(__a1);"; + break; + } + case OpFcvtxnHi: { + s = TypeString(proto[1], typestr) + " __a1 = " + + MangleName("vcvtx_f32", typestr, ClassS) + "(__b);\n " + + "return __builtin_shufflevector(__a, __a1"; + for (unsigned i = 0; i < nElts * 4; ++i) + s += ", " + utostr(i); + s += ");"; + break; + } + case OpUzp1: + s += "__builtin_shufflevector(__a, __b"; + for (unsigned i = 0; i < nElts; i++) + s += ", " + utostr(2*i); + s += ");"; + break; + case OpUzp2: + s += "__builtin_shufflevector(__a, __b"; + for (unsigned i = 0; i < nElts; i++) + s += ", " + utostr(2*i+1); + s += ");"; + break; + case OpZip1: + s += "__builtin_shufflevector(__a, __b"; + for (unsigned i = 0; i < (nElts/2); i++) + s += ", " + utostr(i) + ", " + utostr(i+nElts); + s += ");"; + break; + case OpZip2: + s += "__builtin_shufflevector(__a, __b"; + for (unsigned i = nElts/2; i < nElts; i++) + s += ", " + utostr(i) + ", " + utostr(i+nElts); + s += ");"; + break; + case OpTrn1: + s += "__builtin_shufflevector(__a, __b"; + for (unsigned i = 0; i < (nElts/2); i++) + s += ", " + utostr(2*i) + ", " + utostr(2*i+nElts); + s += ");"; + break; + case OpTrn2: + s += "__builtin_shufflevector(__a, __b"; + for (unsigned i = 0; i < (nElts/2); i++) + s += ", " + utostr(2*i+1) + ", " + utostr(2*i+1+nElts); + s += ");"; + break; case OpAbdl: { std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; if (typestr[0] != 'U') { @@ -1468,23 +1999,247 @@ static std::string GenOpString(OpKind op, const std::string &proto, } break; } + case OpAbdlHi: + s += Gen2OpWith2High(typestr, "vabdl", "__a", "__b"); + break; + case OpAddhnHi: { + std::string addhn = MangleName("vaddhn", typestr, ClassS) + "(__b, __c)"; + s += GenCombine(GetNarrowTypestr(typestr), "__a", addhn); + s += ";"; + break; + } + case OpRAddhnHi: { + std::string raddhn = MangleName("vraddhn", typestr, ClassS) + "(__b, __c)"; + s += GenCombine(GetNarrowTypestr(typestr), "__a", raddhn); + s += ";"; + break; + } + case OpSubhnHi: { + std::string subhn = MangleName("vsubhn", typestr, ClassS) + "(__b, __c)"; + s += GenCombine(GetNarrowTypestr(typestr), "__a", subhn); + s += ";"; + break; + } + case OpRSubhnHi: { + std::string rsubhn = MangleName("vrsubhn", typestr, ClassS) + "(__b, __c)"; + s += GenCombine(GetNarrowTypestr(typestr), "__a", rsubhn); + s += ";"; + break; + } case OpAba: s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);"; break; - case OpAbal: { - s += "__a + "; - std::string abd = MangleName("vabd", typestr, ClassS) + "(__b, __c)"; - if (typestr[0] != 'U') { - // vabd results are always unsigned and must be zero-extended. - std::string utype = "U" + typestr.str(); - s += "(" + TypeString(proto[0], typestr) + ")"; - abd = "(" + TypeString('d', utype) + ")" + abd; - s += Extend(utype, abd) + ";"; + case OpAbal: + s += "__a + " + MangleName("vabdl", typestr, ClassS) + "(__b, __c);"; + break; + case OpAbalHi: + s += Gen3OpWith2High(typestr, "vabal", "__a", "__b", "__c"); + break; + case OpQDMullHi: + s += Gen2OpWith2High(typestr, "vqdmull", "__a", "__b"); + break; + case OpQDMullHiN: + s += MangleName("vqdmull_n", typestr, ClassS); + s += "(" + GetHigh("__a", typestr) + ", __b);"; + return s; + case OpQDMlalHi: + s += Gen3OpWith2High(typestr, "vqdmlal", "__a", "__b", "__c"); + break; + case OpQDMlalHiN: + s += MangleName("vqdmlal_n", typestr, ClassS); + s += "(__a, " + GetHigh("__b", typestr) + ", __c);"; + return s; + case OpQDMlslHi: + s += Gen3OpWith2High(typestr, "vqdmlsl", "__a", "__b", "__c"); + break; + case OpQDMlslHiN: + s += MangleName("vqdmlsl_n", typestr, ClassS); + s += "(__a, " + GetHigh("__b", typestr) + ", __c);"; + return s; + case OpDiv: + s += "__a / __b;"; + break; + case OpMovlHi: { + s = TypeString(proto[1], typestr.drop_front()) + " __a1 = " + + MangleName("vget_high", typestr, ClassS) + "(__a);\n " + s; + s += "(" + ts + ")" + MangleName("vshll_n", typestr, ClassS); + s += "(__a1, 0);"; + break; + } + case OpLongHi: { + // Another local variable __a1 is needed for calling a Macro, + // or using __a will have naming conflict when Macro expanding. + s += TypeString(proto[1], typestr.drop_front()) + " __a1 = " + + MangleName("vget_high", typestr, ClassS) + "(__a); \\\n"; + s += " (" + ts + ")" + MangleName(RemoveHigh(name), typestr, ClassS) + + "(__a1, __b);"; + break; + } + case OpNarrowHi: { + s += "(" + ts + ")" + MangleName("vcombine", typestr, ClassS) + "(__a, " + + MangleName(RemoveHigh(name), typestr, ClassS) + "(__b, __c));"; + break; + } + case OpCopyLane: { + s += TypeString('s', typestr) + " __c2 = " + + MangleName("vget_lane", typestr, ClassS) + "(__c1, __d1); \\\n " + + MangleName("vset_lane", typestr, ClassS) + "(__c2, __a1, __b1);"; + break; + } + case OpCopyQLane: { + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += TypeString('s', typestr) + " __c2 = vget_lane_" + typeCode + + "(__c1, __d1); \\\n vsetq_lane_" + typeCode + "(__c2, __a1, __b1);"; + break; + } + case OpCopyLaneQ: { + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += TypeString('s', typestr) + " __c2 = vgetq_lane_" + typeCode + + "(__c1, __d1); \\\n vset_lane_" + typeCode + "(__c2, __a1, __b1);"; + break; + } + case OpScalarMulLane: { + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += TypeString('s', typestr) + " __d1 = vget_lane_" + typeCode + + "(__b, __c);\\\n __a * __d1;"; + break; + } + case OpScalarMulLaneQ: { + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += TypeString('s', typestr) + " __d1 = vgetq_lane_" + typeCode + + "(__b, __c);\\\n __a * __d1;"; + break; + } + case OpScalarMulXLane: { + bool dummy = false; + char type = ClassifyType(typestr, dummy, dummy, dummy); + if (type == 'f') type = 's'; + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += TypeString('s', typestr) + " __d1 = vget_lane_" + typeCode + + "(__b, __c);\\\n vmulx" + type + "_" + + typeCode + "(__a, __d1);"; + break; + } + case OpScalarMulXLaneQ: { + bool dummy = false; + char type = ClassifyType(typestr, dummy, dummy, dummy); + if (type == 'f') type = 's'; + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += TypeString('s', typestr) + " __d1 = vgetq_lane_" + + typeCode + "(__b, __c);\\\n vmulx" + type + + "_" + typeCode + "(__a, __d1);"; + break; + } + + case OpScalarVMulXLane: { + bool dummy = false; + char type = ClassifyType(typestr, dummy, dummy, dummy); + if (type == 'f') type = 's'; + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += TypeString('s', typestr) + " __d1 = vget_lane_" + + typeCode + "(__a, 0);\\\n" + + " " + TypeString('s', typestr) + " __e1 = vget_lane_" + + typeCode + "(__b, __c);\\\n" + + " " + TypeString('s', typestr) + " __f1 = vmulx" + type + "_" + + typeCode + "(__d1, __e1);\\\n" + + " " + TypeString('d', typestr) + " __g1;\\\n" + + " vset_lane_" + typeCode + "(__f1, __g1, __c);"; + break; + } + + case OpScalarVMulXLaneQ: { + bool dummy = false; + char type = ClassifyType(typestr, dummy, dummy, dummy); + if (type == 'f') type = 's'; + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += TypeString('s', typestr) + " __d1 = vget_lane_" + + typeCode + "(__a, 0);\\\n" + + " " + TypeString('s', typestr) + " __e1 = vgetq_lane_" + + typeCode + "(__b, __c);\\\n" + + " " + TypeString('s', typestr) + " __f1 = vmulx" + type + "_" + + typeCode + "(__d1, __e1);\\\n" + + " " + TypeString('d', typestr) + " __g1;\\\n" + + " vset_lane_" + typeCode + "(__f1, __g1, 0);"; + break; + } + case OpScalarQDMullLane: { + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += MangleName("vqdmull", typestr, ClassS) + "(__a, " + + "vget_lane_" + typeCode + "(b, __c));"; + break; + } + case OpScalarQDMullLaneQ: { + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += MangleName("vqdmull", typestr, ClassS) + "(__a, " + + "vgetq_lane_" + typeCode + "(b, __c));"; + break; + } + case OpScalarQDMulHiLane: { + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " + + "vget_lane_" + typeCode + "(__b, __c));"; + break; + } + case OpScalarQDMulHiLaneQ: { + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " + + "vgetq_lane_" + typeCode + "(__b, __c));"; + break; + } + case OpScalarQRDMulHiLane: { + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " + + "vget_lane_" + typeCode + "(__b, __c));"; + break; + } + case OpScalarQRDMulHiLaneQ: { + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " + + "vgetq_lane_" + typeCode + "(__b, __c));"; + break; + } + case OpScalarGetLane:{ + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + if (quad) { + s += "int16x8_t __a1 = vreinterpretq_s16_f16(__a);\\\n"; + s += " vgetq_lane_s16(__a1, __b);"; } else { - s += Extend(typestr, abd) + ";"; + s += "int16x4_t __a1 = vreinterpret_s16_f16(__a);\\\n"; + s += " vget_lane_s16(__a1, __b);"; } break; } + case OpScalarSetLane:{ + std::string typeCode = ""; + InstructionTypeCode(typestr, ClassS, quad, typeCode); + s += "int16_t __a1 = (int16_t)__a;\\\n"; + if (quad) { + s += " int16x8_t __b1 = vreinterpretq_s16_f16(b);\\\n"; + s += " int16x8_t __b2 = vsetq_lane_s16(__a1, __b1, __c);\\\n"; + s += " vreinterpretq_f16_s16(__b2);"; + } else { + s += " int16x4_t __b1 = vreinterpret_s16_f16(b);\\\n"; + s += " int16x4_t __b2 = vset_lane_s16(__a1, __b1, __c);\\\n"; + s += " vreinterpret_f16_s16(__b2);"; + } + break; + } + default: PrintFatalError("unknown OpKind!"); } @@ -1494,7 +2249,7 @@ static std::string GenOpString(OpKind op, const std::string &proto, static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { unsigned mod = proto[0]; - if (mod == 'v' || mod == 'f') + if (mod == 'v' || mod == 'f' || mod == 'F') mod = proto[1]; bool quad = false; @@ -1522,7 +2277,7 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { ET = NeonTypeFlags::Int32; break; case 'l': - ET = NeonTypeFlags::Int64; + ET = poly ? NeonTypeFlags::Poly64 : NeonTypeFlags::Int64; break; case 'h': ET = NeonTypeFlags::Float16; @@ -1530,6 +2285,9 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { case 'f': ET = NeonTypeFlags::Float32; break; + case 'd': + ET = NeonTypeFlags::Float64; + break; default: PrintFatalError("unhandled type!"); } @@ -1537,6 +2295,19 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { return Flags.getFlags(); } +// We don't check 'a' in this function, because for builtin function the +// argument matching to 'a' uses a vector type splatted from a scalar type. +static bool ProtoHasScalar(const std::string proto) +{ + return (proto.find('s') != std::string::npos + || proto.find('z') != std::string::npos + || proto.find('r') != std::string::npos + || proto.find('b') != std::string::npos + || proto.find('$') != std::string::npos + || proto.find('y') != std::string::npos + || proto.find('o') != std::string::npos); +} + // Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a) static std::string GenBuiltin(const std::string &name, const std::string &proto, StringRef typestr, ClassKind ck) { @@ -1544,14 +2315,14 @@ static std::string GenBuiltin(const std::string &name, const std::string &proto, // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit // sret-like argument. - bool sret = (proto[0] >= '2' && proto[0] <= '4'); + bool sret = IsMultiVecProto(proto[0]); bool define = UseMacro(proto); // Check if the prototype has a scalar operand with the type of the vector // elements. If not, bitcasting the args will take care of arg checking. // The actual signedness etc. will be taken care of with special enums. - if (proto.find('s') == std::string::npos) + if (!ProtoHasScalar(proto)) ck = ClassB; if (proto[0] != 'v') { @@ -1604,12 +2375,19 @@ static std::string GenBuiltin(const std::string &name, const std::string &proto, // Handle multiple-vector values specially, emitting each subvector as an // argument to the __builtin. + unsigned NumOfVec = 0; if (proto[i] >= '2' && proto[i] <= '4') { + NumOfVec = proto[i] - '0'; + } else if (proto[i] >= 'B' && proto[i] <= 'D') { + NumOfVec = proto[i] - 'A' + 1; + } + + if (NumOfVec > 0) { // Check if an explicit cast is needed. if (argType != 'c' || argPoly || argUsgn) args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args; - for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) { + for (unsigned vi = 0, ve = NumOfVec; vi != ve; ++vi) { s += args + ".val[" + utostr(vi) + "]"; if ((vi + 1) < ve) s += ", "; @@ -1662,7 +2440,7 @@ static std::string GenBuiltinDef(const std::string &name, // If all types are the same size, bitcasting the args will take care // of arg checking. The actual signedness etc. will be taken care of with // special enums. - if (proto.find('s') == std::string::npos) + if (!ProtoHasScalar(proto)) ck = ClassB; s += MangleName(name, typestr, ck); @@ -1706,12 +2484,12 @@ static std::string GenIntrinsic(const std::string &name, s += mangledName; // Function arguments - s += GenArgs(proto, inTypeStr); + s += GenArgs(proto, inTypeStr, name); // Definition. if (define) { s += " __extension__ ({ \\\n "; - s += GenMacroLocals(proto, inTypeStr); + s += GenMacroLocals(proto, inTypeStr, name); } else if (kind == OpUnavailable) { s += " __attribute__((unavailable));\n"; return s; @@ -1719,7 +2497,7 @@ static std::string GenIntrinsic(const std::string &name, s += " {\n "; if (kind != OpNone) - s += GenOpString(kind, proto, outTypeStr); + s += GenOpString(name, kind, proto, outTypeStr); else s += GenBuiltin(name, proto, outTypeStr, classKind); if (define) @@ -1773,7 +2551,7 @@ void NeonEmitter::run(raw_ostream &OS) { OS << "#ifndef __ARM_NEON_H\n"; OS << "#define __ARM_NEON_H\n\n"; - OS << "#ifndef __ARM_NEON__\n"; + OS << "#if !defined(__ARM_NEON__) && !defined(__ARM_NEON)\n"; OS << "#error \"NEON support not enabled\"\n"; OS << "#endif\n\n"; @@ -1781,19 +2559,50 @@ void NeonEmitter::run(raw_ostream &OS) { // Emit NEON-specific scalar typedefs. OS << "typedef float float32_t;\n"; + OS << "typedef __fp16 float16_t;\n"; + + OS << "#ifdef __aarch64__\n"; + OS << "typedef double float64_t;\n"; + OS << "#endif\n\n"; + + // For now, signedness of polynomial types depends on target + OS << "#ifdef __aarch64__\n"; + OS << "typedef uint8_t poly8_t;\n"; + OS << "typedef uint16_t poly16_t;\n"; + OS << "typedef uint64_t poly64_t;\n"; + OS << "#else\n"; OS << "typedef int8_t poly8_t;\n"; OS << "typedef int16_t poly16_t;\n"; - OS << "typedef uint16_t float16_t;\n"; + OS << "#endif\n"; // Emit Neon vector typedefs. - std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs"); + std::string TypedefTypes( + "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPsPlQPl"); SmallVector<StringRef, 24> TDTypeVec; ParseTypes(0, TypedefTypes, TDTypeVec); // Emit vector typedefs. + bool isA64 = false; + bool preinsert; + bool postinsert; for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { bool dummy, quad = false, poly = false; - (void) ClassifyType(TDTypeVec[i], quad, poly, dummy); + char type = ClassifyType(TDTypeVec[i], quad, poly, dummy); + preinsert = false; + postinsert = false; + + if (type == 'd' || (type == 'l' && poly)) { + preinsert = isA64? false: true; + isA64 = true; + } else { + postinsert = isA64? true: false; + isA64 = false; + } + if (postinsert) + OS << "#endif\n"; + if (preinsert) + OS << "#ifdef __aarch64__\n"; + if (poly) OS << "typedef __attribute__((neon_polyvector_type("; else @@ -1806,50 +2615,130 @@ void NeonEmitter::run(raw_ostream &OS) { OS << TypeString('s', TDTypeVec[i]); OS << " " << TypeString('d', TDTypeVec[i]) << ";\n"; + } + postinsert = isA64? true: false; + if (postinsert) + OS << "#endif\n"; OS << "\n"; // Emit struct typedefs. + isA64 = false; for (unsigned vi = 2; vi != 5; ++vi) { for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { + bool dummy, quad = false, poly = false; + char type = ClassifyType(TDTypeVec[i], quad, poly, dummy); + preinsert = false; + postinsert = false; + + if (type == 'd' || (type == 'l' && poly)) { + preinsert = isA64? false: true; + isA64 = true; + } else { + postinsert = isA64? true: false; + isA64 = false; + } + if (postinsert) + OS << "#endif\n"; + if (preinsert) + OS << "#ifdef __aarch64__\n"; + std::string ts = TypeString('d', TDTypeVec[i]); std::string vs = TypeString('0' + vi, TDTypeVec[i]); OS << "typedef struct " << vs << " {\n"; OS << " " << ts << " val"; OS << "[" << utostr(vi) << "]"; OS << ";\n} "; - OS << vs << ";\n\n"; + OS << vs << ";\n"; + OS << "\n"; } } + postinsert = isA64? true: false; + if (postinsert) + OS << "#endif\n"; + OS << "\n"; OS<<"#define __ai static inline __attribute__((__always_inline__, __nodebug__))\n\n"; std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); + StringMap<ClassKind> EmittedMap; + // Emit vmovl, vmull and vabd intrinsics first so they can be used by other // intrinsics. (Some of the saturating multiply instructions are also // used to implement the corresponding "_lane" variants, but tablegen // sorts the records into alphabetical order so that the "_lane" variants // come after the intrinsics they use.) - emitIntrinsic(OS, Records.getDef("VMOVL")); - emitIntrinsic(OS, Records.getDef("VMULL")); - emitIntrinsic(OS, Records.getDef("VABD")); - + emitIntrinsic(OS, Records.getDef("VMOVL"), EmittedMap); + emitIntrinsic(OS, Records.getDef("VMULL"), EmittedMap); + emitIntrinsic(OS, Records.getDef("VABD"), EmittedMap); + emitIntrinsic(OS, Records.getDef("VABDL"), EmittedMap); + + // ARM intrinsics must be emitted before AArch64 intrinsics to ensure + // common intrinsics appear only once in the output stream. + // The check for uniquiness is done in emitIntrinsic. + // Emit ARM intrinsics. for (unsigned i = 0, e = RV.size(); i != e; ++i) { Record *R = RV[i]; - if (R->getName() != "VMOVL" && - R->getName() != "VMULL" && + + // Skip AArch64 intrinsics; they will be emitted at the end. + bool isA64 = R->getValueAsBit("isA64"); + if (isA64) + continue; + + if (R->getName() != "VMOVL" && R->getName() != "VMULL" && R->getName() != "VABD") - emitIntrinsic(OS, R); + emitIntrinsic(OS, R, EmittedMap); + } + + // Emit AArch64-specific intrinsics. + OS << "#ifdef __aarch64__\n"; + + emitIntrinsic(OS, Records.getDef("VMOVL_HIGH"), EmittedMap); + emitIntrinsic(OS, Records.getDef("VMULL_HIGH"), EmittedMap); + emitIntrinsic(OS, Records.getDef("VABDL_HIGH"), EmittedMap); + + for (unsigned i = 0, e = RV.size(); i != e; ++i) { + Record *R = RV[i]; + + // Skip ARM intrinsics already included above. + bool isA64 = R->getValueAsBit("isA64"); + if (!isA64) + continue; + + // Skip crypto temporarily, and will emit them all together at the end. + bool isCrypto = R->getValueAsBit("isCrypto"); + if (isCrypto) + continue; + + emitIntrinsic(OS, R, EmittedMap); + } + + OS << "#ifdef __ARM_FEATURE_CRYPTO\n"; + + for (unsigned i = 0, e = RV.size(); i != e; ++i) { + Record *R = RV[i]; + + // Skip crypto temporarily, and will emit them all together at the end. + bool isCrypto = R->getValueAsBit("isCrypto"); + if (!isCrypto) + continue; + + emitIntrinsic(OS, R, EmittedMap); } + + OS << "#endif\n\n"; + + OS << "#endif\n\n"; OS << "#undef __ai\n\n"; OS << "#endif /* __ARM_NEON_H */\n"; } /// emitIntrinsic - Write out the arm_neon.h header file definitions for the -/// intrinsics specified by record R. -void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) { +/// intrinsics specified by record R checking for intrinsic uniqueness. +void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R, + StringMap<ClassKind> &EmittedMap) { std::string name = R->getValueAsString("Name"); std::string Proto = R->getValueAsString("Prototype"); std::string Types = R->getValueAsString("Types"); @@ -1876,12 +2765,20 @@ void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) { (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); if (srcti == ti || inQuad != outQuad) continue; - OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti], - OpCast, ClassS); + std::string s = GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti], + OpCast, ClassS); + if (EmittedMap.count(s)) + continue; + EmittedMap[s] = ClassS; + OS << s; } } else { - OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], - kind, classKind); + std::string s = + GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], kind, classKind); + if (EmittedMap.count(s)) + continue; + EmittedMap[s] = classKind; + OS << s; } } OS << "\n"; @@ -1902,6 +2799,7 @@ static unsigned RangeFromType(const char mod, StringRef typestr) { case 'f': case 'i': return (2 << (int)quad) - 1; + case 'd': case 'l': return (1 << (int)quad) - 1; default: @@ -1909,56 +2807,198 @@ static unsigned RangeFromType(const char mod, StringRef typestr) { } } -/// runHeader - Emit a file with sections defining: -/// 1. the NEON section of BuiltinsARM.def. -/// 2. the SemaChecking code for the type overload checking. -/// 3. the SemaChecking code for validation of intrinsic immediate arguments. -void NeonEmitter::runHeader(raw_ostream &OS) { - std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); +static unsigned RangeScalarShiftImm(const char mod, StringRef typestr) { + // base type to get the type string for. + bool dummy = false; + char type = ClassifyType(typestr, dummy, dummy, dummy); + type = ModType(mod, type, dummy, dummy, dummy, dummy, dummy, dummy); + switch (type) { + case 'c': + return 7; + case 'h': + case 's': + return 15; + case 'f': + case 'i': + return 31; + case 'd': + case 'l': + return 63; + default: + PrintFatalError("unhandled type!"); + } +} + +/// Generate the ARM and AArch64 intrinsic range checking code for +/// shift/lane immediates, checking for unique declarations. +void +NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS, + StringMap<ClassKind> &A64IntrinsicMap, + bool isA64RangeCheck) { + std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); StringMap<OpKind> EmittedMap; - // Generate BuiltinsARM.def for NEON - OS << "#ifdef GET_NEON_BUILTINS\n"; + // Generate the intrinsic range checking code for shift/lane immediates. + if (isA64RangeCheck) + OS << "#ifdef GET_NEON_AARCH64_IMMEDIATE_CHECK\n"; + else + OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n"; + for (unsigned i = 0, e = RV.size(); i != e; ++i) { Record *R = RV[i]; + OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; if (k != OpNone) continue; + std::string name = R->getValueAsString("Name"); std::string Proto = R->getValueAsString("Prototype"); + std::string Types = R->getValueAsString("Types"); + std::string Rename = name + "@" + Proto; // Functions with 'a' (the splat code) in the type prototype should not get // their own builtin as they use the non-splat variant. if (Proto.find('a') != std::string::npos) continue; - std::string Types = R->getValueAsString("Types"); + // Functions which do not have an immediate do not need to have range + // checking code emitted. + size_t immPos = Proto.find('i'); + if (immPos == std::string::npos) + continue; + SmallVector<StringRef, 16> TypeVec; ParseTypes(R, Types, TypeVec); if (R->getSuperClasses().size() < 2) PrintFatalError(R->getLoc(), "Builtin has no class kind"); - std::string name = R->getValueAsString("Name"); ClassKind ck = ClassMap[R->getSuperClasses()[1]]; + if (!ProtoHasScalar(Proto)) + ck = ClassB; + + // Do not include AArch64 range checks if not generating code for AArch64. + bool isA64 = R->getValueAsBit("isA64"); + if (!isA64RangeCheck && isA64) + continue; + + // Include ARM range checks in AArch64 but only if ARM intrinsics are not + // redefined by AArch64 to handle new types. + if (isA64RangeCheck && !isA64 && A64IntrinsicMap.count(Rename)) { + ClassKind &A64CK = A64IntrinsicMap[Rename]; + if (A64CK == ck && ck != ClassNone) + continue; + } for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { - // Generate the BuiltinsARM.def declaration for this builtin, ensuring - // that each unique BUILTIN() macro appears only once in the output - // stream. - std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck); - if (EmittedMap.count(bd)) + std::string namestr, shiftstr, rangestr; + + if (R->getValueAsBit("isVCVT_N")) { + // VCVT between floating- and fixed-point values takes an immediate + // in the range [1, 32] for f32, or [1, 64] for f64. + ck = ClassB; + if (name.find("32") != std::string::npos) + rangestr = "l = 1; u = 31"; // upper bound = l + u + else if (name.find("64") != std::string::npos) + rangestr = "l = 1; u = 63"; + else + PrintFatalError(R->getLoc(), + "Fixed point convert name should contains \"32\" or \"64\""); + + } else if (R->getValueAsBit("isScalarShift")) { + // Right shifts have an 'r' in the name, left shifts do not. Convert + // instructions have the same bounds and right shifts. + if (name.find('r') != std::string::npos || + name.find("cvt") != std::string::npos) + rangestr = "l = 1; "; + + unsigned upBound = RangeScalarShiftImm(Proto[immPos - 1], TypeVec[ti]); + // Narrow shift has half the upper bound + if (R->getValueAsBit("isScalarNarrowShift")) + upBound /= 2; + + rangestr += "u = " + utostr(upBound); + } else if (R->getValueAsBit("isShift")) { + // Builtins which are overloaded by type will need to have their upper + // bound computed at Sema time based on the type constant. + shiftstr = ", true"; + + // Right shifts have an 'r' in the name, left shifts do not. + if (name.find('r') != std::string::npos) + rangestr = "l = 1; "; + + rangestr += "u = RFT(TV" + shiftstr + ")"; + } else { + // The immediate generally refers to a lane in the preceding argument. + assert(immPos > 0 && "unexpected immediate operand"); + rangestr = + "u = " + utostr(RangeFromType(Proto[immPos - 1], TypeVec[ti])); + } + // Make sure cases appear only once by uniquing them in a string map. + namestr = MangleName(name, TypeVec[ti], ck); + if (EmittedMap.count(namestr)) continue; + EmittedMap[namestr] = OpNone; - EmittedMap[bd] = OpNone; - OS << bd << "\n"; + // Calculate the index of the immediate that should be range checked. + unsigned immidx = 0; + + // Builtins that return a struct of multiple vectors have an extra + // leading arg for the struct return. + if (IsMultiVecProto(Proto[0])) + ++immidx; + + // Add one to the index for each argument until we reach the immediate + // to be checked. Structs of vectors are passed as multiple arguments. + for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) { + switch (Proto[ii]) { + default: + immidx += 1; + break; + case '2': + case 'B': + immidx += 2; + break; + case '3': + case 'C': + immidx += 3; + break; + case '4': + case 'D': + immidx += 4; + break; + case 'i': + ie = ii + 1; + break; + } + } + if (isA64RangeCheck) + OS << "case AArch64::BI__builtin_neon_"; + else + OS << "case ARM::BI__builtin_neon_"; + OS << MangleName(name, TypeVec[ti], ck) << ": i = " << immidx << "; " + << rangestr << "; break;\n"; } } OS << "#endif\n\n"; +} + +/// Generate the ARM and AArch64 overloaded type checking code for +/// SemaChecking.cpp, checking for unique builtin declarations. +void +NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS, + StringMap<ClassKind> &A64IntrinsicMap, + bool isA64TypeCheck) { + std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); + StringMap<OpKind> EmittedMap; // Generate the overloaded type checking code for SemaChecking.cpp - OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n"; + if (isA64TypeCheck) + OS << "#ifdef GET_NEON_AARCH64_OVERLOAD_CHECK\n"; + else + OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n"; + for (unsigned i = 0, e = RV.size(); i != e; ++i) { Record *R = RV[i]; OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; @@ -1968,7 +3008,8 @@ void NeonEmitter::runHeader(raw_ostream &OS) { std::string Proto = R->getValueAsString("Prototype"); std::string Types = R->getValueAsString("Types"); std::string name = R->getValueAsString("Name"); - + std::string Rename = name + "@" + Proto; + // Functions with 'a' (the splat code) in the type prototype should not get // their own builtin as they use the non-splat variant. if (Proto.find('a') != std::string::npos) @@ -1976,7 +3017,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) { // Functions which have a scalar argument cannot be overloaded, no need to // check them if we are emitting the type checking code. - if (Proto.find('s') != std::string::npos) + if (ProtoHasScalar(Proto)) continue; SmallVector<StringRef, 16> TypeVec; @@ -1985,6 +3026,21 @@ void NeonEmitter::runHeader(raw_ostream &OS) { if (R->getSuperClasses().size() < 2) PrintFatalError(R->getLoc(), "Builtin has no class kind"); + // Do not include AArch64 type checks if not generating code for AArch64. + bool isA64 = R->getValueAsBit("isA64"); + if (!isA64TypeCheck && isA64) + continue; + + // Include ARM type check in AArch64 but only if ARM intrinsics + // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr + // redefined in AArch64 to handle an additional 2 x f64 type. + ClassKind ck = ClassMap[R->getSuperClasses()[1]]; + if (isA64TypeCheck && !isA64 && A64IntrinsicMap.count(Rename)) { + ClassKind &A64CK = A64IntrinsicMap[Rename]; + if (A64CK == ck && ck != ClassNone) + continue; + } + int si = -1, qi = -1; uint64_t mask = 0, qmask = 0; for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { @@ -2017,7 +3073,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) { } } // For sret builtins, adjust the pointer argument index. - if (PtrArgNum >= 0 && (Proto[0] >= '2' && Proto[0] <= '4')) + if (PtrArgNum >= 0 && IsMultiVecProto(Proto[0])) PtrArgNum += 1; // Omit type checking for the pointer arguments of vld1_lane, vld1_dup, @@ -2032,9 +3088,12 @@ void NeonEmitter::runHeader(raw_ostream &OS) { } if (mask) { - OS << "case ARM::BI__builtin_neon_" - << MangleName(name, TypeVec[si], ClassB) - << ": mask = " << "0x" << utohexstr(mask) << "ULL"; + if (isA64TypeCheck) + OS << "case AArch64::BI__builtin_neon_"; + else + OS << "case ARM::BI__builtin_neon_"; + OS << MangleName(name, TypeVec[si], ClassB) << ": mask = " + << "0x" << utohexstr(mask) << "ULL"; if (PtrArgNum >= 0) OS << "; PtrArgNum = " << PtrArgNum; if (HasConstPtr) @@ -2042,9 +3101,12 @@ void NeonEmitter::runHeader(raw_ostream &OS) { OS << "; break;\n"; } if (qmask) { - OS << "case ARM::BI__builtin_neon_" - << MangleName(name, TypeVec[qi], ClassB) - << ": mask = " << "0x" << utohexstr(qmask) << "ULL"; + if (isA64TypeCheck) + OS << "case AArch64::BI__builtin_neon_"; + else + OS << "case ARM::BI__builtin_neon_"; + OS << MangleName(name, TypeVec[qi], ClassB) << ": mask = " + << "0x" << utohexstr(qmask) << "ULL"; if (PtrArgNum >= 0) OS << "; PtrArgNum = " << PtrArgNum; if (HasConstPtr) @@ -2053,31 +3115,38 @@ void NeonEmitter::runHeader(raw_ostream &OS) { } } OS << "#endif\n\n"; +} + +/// genBuiltinsDef: Generate the BuiltinsARM.def and BuiltinsAArch64.def +/// declaration of builtins, checking for unique builtin declarations. +void NeonEmitter::genBuiltinsDef(raw_ostream &OS, + StringMap<ClassKind> &A64IntrinsicMap, + bool isA64GenBuiltinDef) { + std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); + StringMap<OpKind> EmittedMap; + + // Generate BuiltinsARM.def and BuiltinsAArch64.def + if (isA64GenBuiltinDef) + OS << "#ifdef GET_NEON_AARCH64_BUILTINS\n"; + else + OS << "#ifdef GET_NEON_BUILTINS\n"; - // Generate the intrinsic range checking code for shift/lane immediates. - OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n"; for (unsigned i = 0, e = RV.size(); i != e; ++i) { Record *R = RV[i]; - OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; if (k != OpNone) continue; - std::string name = R->getValueAsString("Name"); std::string Proto = R->getValueAsString("Prototype"); - std::string Types = R->getValueAsString("Types"); + std::string name = R->getValueAsString("Name"); + std::string Rename = name + "@" + Proto; // Functions with 'a' (the splat code) in the type prototype should not get // their own builtin as they use the non-splat variant. if (Proto.find('a') != std::string::npos) continue; - // Functions which do not have an immediate do not need to have range - // checking code emitted. - size_t immPos = Proto.find('i'); - if (immPos == std::string::npos) - continue; - + std::string Types = R->getValueAsString("Types"); SmallVector<StringRef, 16> TypeVec; ParseTypes(R, Types, TypeVec); @@ -2086,70 +3155,92 @@ void NeonEmitter::runHeader(raw_ostream &OS) { ClassKind ck = ClassMap[R->getSuperClasses()[1]]; - for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { - std::string namestr, shiftstr, rangestr; - - if (R->getValueAsBit("isVCVT_N")) { - // VCVT between floating- and fixed-point values takes an immediate - // in the range 1 to 32. - ck = ClassB; - rangestr = "l = 1; u = 31"; // upper bound = l + u - } else if (Proto.find('s') == std::string::npos) { - // Builtins which are overloaded by type will need to have their upper - // bound computed at Sema time based on the type constant. - ck = ClassB; - if (R->getValueAsBit("isShift")) { - shiftstr = ", true"; + // Do not include AArch64 BUILTIN() macros if not generating + // code for AArch64 + bool isA64 = R->getValueAsBit("isA64"); + if (!isA64GenBuiltinDef && isA64) + continue; - // Right shifts have an 'r' in the name, left shifts do not. - if (name.find('r') != std::string::npos) - rangestr = "l = 1; "; - } - rangestr += "u = RFT(TV" + shiftstr + ")"; - } else { - // The immediate generally refers to a lane in the preceding argument. - assert(immPos > 0 && "unexpected immediate operand"); - rangestr = "u = " + utostr(RangeFromType(Proto[immPos-1], TypeVec[ti])); - } - // Make sure cases appear only once by uniquing them in a string map. - namestr = MangleName(name, TypeVec[ti], ck); - if (EmittedMap.count(namestr)) + // Include ARM BUILTIN() macros in AArch64 but only if ARM intrinsics + // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr + // redefined in AArch64 to handle an additional 2 x f64 type. + if (isA64GenBuiltinDef && !isA64 && A64IntrinsicMap.count(Rename)) { + ClassKind &A64CK = A64IntrinsicMap[Rename]; + if (A64CK == ck && ck != ClassNone) continue; - EmittedMap[namestr] = OpNone; - - // Calculate the index of the immediate that should be range checked. - unsigned immidx = 0; + } - // Builtins that return a struct of multiple vectors have an extra - // leading arg for the struct return. - if (Proto[0] >= '2' && Proto[0] <= '4') - ++immidx; + for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { + // Generate the declaration for this builtin, ensuring + // that each unique BUILTIN() macro appears only once in the output + // stream. + std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck); + if (EmittedMap.count(bd)) + continue; - // Add one to the index for each argument until we reach the immediate - // to be checked. Structs of vectors are passed as multiple arguments. - for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) { - switch (Proto[ii]) { - default: immidx += 1; break; - case '2': immidx += 2; break; - case '3': immidx += 3; break; - case '4': immidx += 4; break; - case 'i': ie = ii + 1; break; - } - } - OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck) - << ": i = " << immidx << "; " << rangestr << "; break;\n"; + EmittedMap[bd] = OpNone; + OS << bd << "\n"; } } OS << "#endif\n\n"; } +/// runHeader - Emit a file with sections defining: +/// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def. +/// 2. the SemaChecking code for the type overload checking. +/// 3. the SemaChecking code for validation of intrinsic immediate arguments. +void NeonEmitter::runHeader(raw_ostream &OS) { + std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); + + // build a map of AArch64 intriniscs to be used in uniqueness checks. + StringMap<ClassKind> A64IntrinsicMap; + for (unsigned i = 0, e = RV.size(); i != e; ++i) { + Record *R = RV[i]; + + bool isA64 = R->getValueAsBit("isA64"); + if (!isA64) + continue; + + ClassKind CK = ClassNone; + if (R->getSuperClasses().size() >= 2) + CK = ClassMap[R->getSuperClasses()[1]]; + + std::string Name = R->getValueAsString("Name"); + std::string Proto = R->getValueAsString("Prototype"); + std::string Rename = Name + "@" + Proto; + if (A64IntrinsicMap.count(Rename)) + continue; + A64IntrinsicMap[Rename] = CK; + } + + // Generate BuiltinsARM.def for ARM + genBuiltinsDef(OS, A64IntrinsicMap, false); + + // Generate BuiltinsAArch64.def for AArch64 + genBuiltinsDef(OS, A64IntrinsicMap, true); + + // Generate ARM overloaded type checking code for SemaChecking.cpp + genOverloadTypeCheckCode(OS, A64IntrinsicMap, false); + + // Generate AArch64 overloaded type checking code for SemaChecking.cpp + genOverloadTypeCheckCode(OS, A64IntrinsicMap, true); + + // Generate ARM range checking code for shift/lane immediates. + genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, false); + + // Generate the AArch64 range checking code for shift/lane immediates. + genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, true); +} + /// GenTest - Write out a test for the intrinsic specified by the name and /// type strings, including the embedded patterns for FileCheck to match. static std::string GenTest(const std::string &name, const std::string &proto, StringRef outTypeStr, StringRef inTypeStr, bool isShift, bool isHiddenLOp, - ClassKind ck, const std::string &InstName) { + ClassKind ck, const std::string &InstName, + bool isA64, + std::string & testFuncProto) { assert(!proto.empty() && ""); std::string s; @@ -2164,12 +3255,17 @@ static std::string GenTest(const std::string &name, mangledName = MangleName(mangledName, inTypeNoQuad, ClassS); } + // todo: GenerateChecksForIntrinsic does not generate CHECK + // for aarch64 instructions yet std::vector<std::string> FileCheckPatterns; - GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName, - isHiddenLOp, FileCheckPatterns); + if (!isA64) { + GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName, + isHiddenLOp, FileCheckPatterns); + s+= "// CHECK_ARM: test_" + mangledName + "\n"; + } + s += "// CHECK_AARCH64: test_" + mangledName + "\n"; // Emit the FileCheck patterns. - s += "// CHECK: test_" + mangledName + "\n"; // If for any reason we do not want to emit a check, mangledInst // will be the empty string. if (FileCheckPatterns.size()) { @@ -2177,23 +3273,27 @@ static std::string GenTest(const std::string &name, e = FileCheckPatterns.end(); i != e; ++i) { - s += "// CHECK: " + *i + "\n"; + s += "// CHECK_ARM: " + *i + "\n"; } } // Emit the start of the test function. - s += TypeString(proto[0], outTypeStr) + " test_" + mangledName + "("; + + testFuncProto = TypeString(proto[0], outTypeStr) + " test_" + mangledName + "("; char arg = 'a'; std::string comma; for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { // Do not create arguments for values that must be immediate constants. if (proto[i] == 'i') continue; - s += comma + TypeString(proto[i], inTypeStr) + " "; - s.push_back(arg); + testFuncProto += comma + TypeString(proto[i], inTypeStr) + " "; + testFuncProto.push_back(arg); comma = ", "; } - s += ") {\n "; + testFuncProto += ")"; + + s+= testFuncProto; + s+= " {\n "; if (proto[0] != 'v') s += "return "; @@ -2217,18 +3317,14 @@ static std::string GenTest(const std::string &name, return s; } -/// runTests - Write out a complete set of tests for all of the Neon -/// intrinsics. -void NeonEmitter::runTests(raw_ostream &OS) { - OS << - "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi apcs-gnu\\\n" - "// RUN: -target-cpu swift -ffreestanding -Os -S -o - %s\\\n" - "// RUN: | FileCheck %s\n" - "\n" - "#include <arm_neon.h>\n" - "\n"; +/// Write out all intrinsic tests for the specified target, checking +/// for intrinsic test uniqueness. +void NeonEmitter::genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap, + bool isA64GenTest) { + if (isA64GenTest) + OS << "#ifdef __aarch64__\n"; - std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); + std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); for (unsigned i = 0, e = RV.size(); i != e; ++i) { Record *R = RV[i]; std::string name = R->getValueAsString("Name"); @@ -2237,6 +3333,12 @@ void NeonEmitter::runTests(raw_ostream &OS) { bool isShift = R->getValueAsBit("isShift"); std::string InstName = R->getValueAsString("InstName"); bool isHiddenLOp = R->getValueAsBit("isHiddenLInst"); + bool isA64 = R->getValueAsBit("isA64"); + + // do not include AArch64 intrinsic test if not generating + // code for AArch64 + if (!isA64GenTest && isA64) + continue; SmallVector<StringRef, 16> TypeVec; ParseTypes(R, Types, TypeVec); @@ -2256,16 +3358,56 @@ void NeonEmitter::runTests(raw_ostream &OS) { (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); if (srcti == ti || inQuad != outQuad) continue; - OS << GenTest(name, Proto, TypeVec[ti], TypeVec[srcti], - isShift, isHiddenLOp, ck, InstName); + std::string testFuncProto; + std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[srcti], + isShift, isHiddenLOp, ck, InstName, isA64, + testFuncProto); + if (EmittedMap.count(testFuncProto)) + continue; + EmittedMap[testFuncProto] = kind; + OS << s << "\n"; } } else { - OS << GenTest(name, Proto, TypeVec[ti], TypeVec[ti], - isShift, isHiddenLOp, ck, InstName); + std::string testFuncProto; + std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift, + isHiddenLOp, ck, InstName, isA64, testFuncProto); + if (EmittedMap.count(testFuncProto)) + continue; + EmittedMap[testFuncProto] = kind; + OS << s << "\n"; } } - OS << "\n"; } + + if (isA64GenTest) + OS << "#endif\n"; +} +/// runTests - Write out a complete set of tests for all of the Neon +/// intrinsics. +void NeonEmitter::runTests(raw_ostream &OS) { + OS << "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi " + "apcs-gnu\\\n" + "// RUN: -target-cpu swift -ffreestanding -Os -S -o - %s\\\n" + "// RUN: | FileCheck %s -check-prefix=CHECK_ARM\n" + "\n" + "// RUN: %clang_cc1 -triple aarch64-none-linux-gnu \\\n" + "// RUN -target-feature +neon -ffreestanding -S -o - %s \\\n" + "// RUN: | FileCheck %s -check-prefix=CHECK_AARCH64\n" + "\n" + "// REQUIRES: long_tests\n" + "\n" + "#include <arm_neon.h>\n" + "\n"; + + // ARM tests must be emitted before AArch64 tests to ensure + // tests for intrinsics that are common to ARM and AArch64 + // appear only once in the output stream. + // The check for uniqueness is done in genTargetTest. + StringMap<OpKind> EmittedMap; + + genTargetTest(OS, EmittedMap, false); + + genTargetTest(OS, EmittedMap, true); } namespace clang { diff --git a/contrib/llvm/tools/clang/utils/TableGen/OptParserEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/OptParserEmitter.cpp deleted file mode 100644 index 0553b1f..0000000 --- a/contrib/llvm/tools/clang/utils/TableGen/OptParserEmitter.cpp +++ /dev/null @@ -1,275 +0,0 @@ -//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Twine.h" -#include "llvm/TableGen/Error.h" -#include "llvm/TableGen/Record.h" -#include "llvm/TableGen/TableGenBackend.h" -#include <map> - -using namespace llvm; - -static int StrCmpOptionName(const char *A, const char *B) { - char a = *A, b = *B; - while (a == b) { - if (a == '\0') - return 0; - - a = *++A; - b = *++B; - } - - if (a == '\0') // A is a prefix of B. - return 1; - if (b == '\0') // B is a prefix of A. - return -1; - - // Otherwise lexicographic. - return (a < b) ? -1 : 1; -} - -static int CompareOptionRecords(const void *Av, const void *Bv) { - const Record *A = *(const Record*const*) Av; - const Record *B = *(const Record*const*) Bv; - - // Sentinel options precede all others and are only ordered by precedence. - bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel"); - bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel"); - if (ASent != BSent) - return ASent ? -1 : 1; - - // Compare options by name, unless they are sentinels. - if (!ASent) - if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(), - B->getValueAsString("Name").c_str())) - return Cmp; - - if (!ASent) { - std::vector<std::string> APrefixes = A->getValueAsListOfStrings("Prefixes"); - std::vector<std::string> BPrefixes = B->getValueAsListOfStrings("Prefixes"); - - for (std::vector<std::string>::const_iterator APre = APrefixes.begin(), - AEPre = APrefixes.end(), - BPre = BPrefixes.begin(), - BEPre = BPrefixes.end(); - APre != AEPre && - BPre != BEPre; - ++APre, ++BPre) { - if (int Cmp = StrCmpOptionName(APre->c_str(), BPre->c_str())) - return Cmp; - } - } - - // Then by the kind precedence; - int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence"); - int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence"); - if (APrec == BPrec && - A->getValueAsListOfStrings("Prefixes") == - B->getValueAsListOfStrings("Prefixes")) { - PrintError(A->getLoc(), Twine("Option is equivilent to")); - PrintError(B->getLoc(), Twine("Other defined here")); - PrintFatalError("Equivalent Options found."); - } - return APrec < BPrec ? -1 : 1; -} - -static const std::string getOptionName(const Record &R) { - // Use the record name unless EnumName is defined. - if (isa<UnsetInit>(R.getValueInit("EnumName"))) - return R.getName(); - - return R.getValueAsString("EnumName"); -} - -static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { - OS << '"'; - OS.write_escaped(Str); - OS << '"'; - return OS; -} - -/// OptParserEmitter - This tablegen backend takes an input .td file -/// describing a list of options and emits a data structure for parsing and -/// working with those options when given an input command line. -namespace clang { -void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) { - // Get the option groups and options. - const std::vector<Record*> &Groups = - Records.getAllDerivedDefinitions("OptionGroup"); - std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option"); - - if (GenDefs) - emitSourceFileHeader("Option Parsing Definitions", OS); - else - emitSourceFileHeader("Option Parsing Table", OS); - - array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords); - if (GenDefs) { - // Generate prefix groups. - typedef SmallVector<SmallString<2>, 2> PrefixKeyT; - typedef std::map<PrefixKeyT, std::string> PrefixesT; - PrefixesT Prefixes; - Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0")); - unsigned CurPrefix = 0; - for (unsigned i = 0, e = Opts.size(); i != e; ++i) { - const Record &R = *Opts[i]; - std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes"); - PrefixKeyT prfkey(prf.begin(), prf.end()); - unsigned NewPrefix = CurPrefix + 1; - if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") + - Twine(NewPrefix)).str())).second) - CurPrefix = NewPrefix; - } - - OS << "#ifndef PREFIX\n"; - OS << "#error \"Define PREFIX prior to including this file!\"\n"; - OS << "#endif\n\n"; - - // Dump prefixes. - OS << "/////////\n"; - OS << "// Prefixes\n\n"; - OS << "#define COMMA ,\n"; - for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end(); - I != E; ++I) { - OS << "PREFIX("; - - // Prefix name. - OS << I->second; - - // Prefix values. - OS << ", {"; - for (PrefixKeyT::const_iterator PI = I->first.begin(), - PE = I->first.end(); PI != PE; ++PI) { - OS << "\"" << *PI << "\" COMMA "; - } - OS << "0})\n"; - } - OS << "#undef COMMA\n"; - OS << "\n"; - - OS << "#ifndef OPTION\n"; - OS << "#error \"Define OPTION prior to including this file!\"\n"; - OS << "#endif\n\n"; - - OS << "/////////\n"; - OS << "// Groups\n\n"; - for (unsigned i = 0, e = Groups.size(); i != e; ++i) { - const Record &R = *Groups[i]; - - // Start a single option entry. - OS << "OPTION("; - - // The option prefix; - OS << "0"; - - // The option string. - OS << ", \"" << R.getValueAsString("Name") << '"'; - - // The option identifier name. - OS << ", "<< getOptionName(R); - - // The option kind. - OS << ", Group"; - - // The containing option group (if any). - OS << ", "; - if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) - OS << getOptionName(*DI->getDef()); - else - OS << "INVALID"; - - // The other option arguments (unused for groups). - OS << ", INVALID, 0, 0"; - - // The option help text. - if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { - OS << ",\n"; - OS << " "; - write_cstring(OS, R.getValueAsString("HelpText")); - } else - OS << ", 0"; - - // The option meta-variable name (unused). - OS << ", 0)\n"; - } - OS << "\n"; - - OS << "//////////\n"; - OS << "// Options\n\n"; - for (unsigned i = 0, e = Opts.size(); i != e; ++i) { - const Record &R = *Opts[i]; - - // Start a single option entry. - OS << "OPTION("; - - // The option prefix; - std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes"); - OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", "; - - // The option string. - write_cstring(OS, R.getValueAsString("Name")); - - // The option identifier name. - OS << ", "<< getOptionName(R); - - // The option kind. - OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name"); - - // The containing option group (if any). - OS << ", "; - if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) - OS << getOptionName(*DI->getDef()); - else - OS << "INVALID"; - - // The option alias (if any). - OS << ", "; - if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias"))) - OS << getOptionName(*DI->getDef()); - else - OS << "INVALID"; - - // The option flags. - const ListInit *LI = R.getValueAsListInit("Flags"); - if (LI->empty()) { - OS << ", 0"; - } else { - OS << ", "; - for (unsigned i = 0, e = LI->size(); i != e; ++i) { - if (i) - OS << " | "; - OS << cast<DefInit>(LI->getElement(i))->getDef()->getName(); - } - } - - // The option parameter field. - OS << ", " << R.getValueAsInt("NumArgs"); - - // The option help text. - if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { - OS << ",\n"; - OS << " "; - write_cstring(OS, R.getValueAsString("HelpText")); - } else - OS << ", 0"; - - // The option meta-variable name. - OS << ", "; - if (!isa<UnsetInit>(R.getValueInit("MetaVarName"))) - write_cstring(OS, R.getValueAsString("MetaVarName")); - else - OS << "0"; - - OS << ")\n"; - } - } -} -} // end namespace clang diff --git a/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp b/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp index 12e1c47..0e45d81 100644 --- a/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp +++ b/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp @@ -24,7 +24,8 @@ using namespace clang; enum ActionType { GenClangAttrClasses, - GenClangAttrExprArgsList, + GenClangAttrIdentifierArgList, + GenClangAttrTypeArgList, GenClangAttrImpl, GenClangAttrList, GenClangAttrPCHRead, @@ -34,6 +35,7 @@ enum ActionType { GenClangAttrLateParsedList, GenClangAttrTemplateInstantiate, GenClangAttrParsedAttrList, + GenClangAttrParsedAttrImpl, GenClangAttrParsedAttrKinds, GenClangAttrDump, GenClangDiagsDefs, @@ -48,108 +50,108 @@ enum ActionType { GenClangCommentHTMLNamedCharacterReferences, GenClangCommentCommandInfo, GenClangCommentCommandList, - GenOptParserDefs, GenOptParserImpl, GenArmNeon, GenArmNeonSema, GenArmNeonTest }; namespace { - cl::opt<ActionType> - Action(cl::desc("Action to perform:"), - cl::values(clEnumValN(GenOptParserDefs, "gen-opt-parser-defs", - "Generate option definitions"), - clEnumValN(GenOptParserImpl, "gen-opt-parser-impl", - "Generate option parser implementation"), - clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes", - "Generate clang attribute clases"), - clEnumValN(GenClangAttrExprArgsList, - "gen-clang-attr-expr-args-list", - "Generate a clang attribute expression " - "arguments list"), - clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl", - "Generate clang attribute implementations"), - clEnumValN(GenClangAttrList, "gen-clang-attr-list", - "Generate a clang attribute list"), - clEnumValN(GenClangAttrPCHRead, "gen-clang-attr-pch-read", - "Generate clang PCH attribute reader"), - clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write", - "Generate clang PCH attribute writer"), - clEnumValN(GenClangAttrSpellingList, - "gen-clang-attr-spelling-list", - "Generate a clang attribute spelling list"), - clEnumValN(GenClangAttrSpellingListIndex, - "gen-clang-attr-spelling-index", - "Generate a clang attribute spelling index"), - clEnumValN(GenClangAttrLateParsedList, - "gen-clang-attr-late-parsed-list", - "Generate a clang attribute LateParsed list"), - clEnumValN(GenClangAttrTemplateInstantiate, - "gen-clang-attr-template-instantiate", - "Generate a clang template instantiate code"), - clEnumValN(GenClangAttrParsedAttrList, - "gen-clang-attr-parsed-attr-list", - "Generate a clang parsed attribute list"), - clEnumValN(GenClangAttrParsedAttrKinds, - "gen-clang-attr-parsed-attr-kinds", - "Generate a clang parsed attribute kinds"), - clEnumValN(GenClangAttrDump, "gen-clang-attr-dump", - "Generate clang attribute dumper"), - clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs", - "Generate Clang diagnostics definitions"), - clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups", - "Generate Clang diagnostic groups"), - clEnumValN(GenClangDiagsIndexName, - "gen-clang-diags-index-name", - "Generate Clang diagnostic name index"), - clEnumValN(GenClangCommentNodes, "gen-clang-comment-nodes", - "Generate Clang AST comment nodes"), - clEnumValN(GenClangDeclNodes, "gen-clang-decl-nodes", - "Generate Clang AST declaration nodes"), - clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes", - "Generate Clang AST statement nodes"), - clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers", - "Generate Clang Static Analyzer checkers"), - clEnumValN(GenClangCommentHTMLTags, - "gen-clang-comment-html-tags", - "Generate efficient matchers for HTML tag " - "names that are used in documentation comments"), - clEnumValN(GenClangCommentHTMLTagsProperties, - "gen-clang-comment-html-tags-properties", - "Generate efficient matchers for HTML tag " - "properties"), - clEnumValN(GenClangCommentHTMLNamedCharacterReferences, - "gen-clang-comment-html-named-character-references", - "Generate function to translate named character " - "references to UTF-8 sequences"), - clEnumValN(GenClangCommentCommandInfo, - "gen-clang-comment-command-info", - "Generate command properties for commands that " - "are used in documentation comments"), - clEnumValN(GenClangCommentCommandList, - "gen-clang-comment-command-list", - "Generate list of commands that are used in " - "documentation comments"), - clEnumValN(GenArmNeon, "gen-arm-neon", - "Generate arm_neon.h for clang"), - clEnumValN(GenArmNeonSema, "gen-arm-neon-sema", - "Generate ARM NEON sema support for clang"), - clEnumValN(GenArmNeonTest, "gen-arm-neon-test", - "Generate ARM NEON tests for clang"), - clEnumValEnd)); +cl::opt<ActionType> Action( + cl::desc("Action to perform:"), + cl::values( + clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes", + "Generate clang attribute clases"), + clEnumValN(GenClangAttrIdentifierArgList, + "gen-clang-attr-identifier-arg-list", + "Generate a list of attributes that take an " + "identifier as their first argument"), + clEnumValN(GenClangAttrTypeArgList, + "gen-clang-attr-type-arg-list", + "Generate a list of attributes that take a type as their " + "first argument"), + clEnumValN(GenClangAttrImpl, "gen-clang-attr-impl", + "Generate clang attribute implementations"), + clEnumValN(GenClangAttrList, "gen-clang-attr-list", + "Generate a clang attribute list"), + clEnumValN(GenClangAttrPCHRead, "gen-clang-attr-pch-read", + "Generate clang PCH attribute reader"), + clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write", + "Generate clang PCH attribute writer"), + clEnumValN(GenClangAttrSpellingList, "gen-clang-attr-spelling-list", + "Generate a clang attribute spelling list"), + clEnumValN(GenClangAttrSpellingListIndex, + "gen-clang-attr-spelling-index", + "Generate a clang attribute spelling index"), + clEnumValN(GenClangAttrLateParsedList, + "gen-clang-attr-late-parsed-list", + "Generate a clang attribute LateParsed list"), + clEnumValN(GenClangAttrTemplateInstantiate, + "gen-clang-attr-template-instantiate", + "Generate a clang template instantiate code"), + clEnumValN(GenClangAttrParsedAttrList, + "gen-clang-attr-parsed-attr-list", + "Generate a clang parsed attribute list"), + clEnumValN(GenClangAttrParsedAttrImpl, + "gen-clang-attr-parsed-attr-impl", + "Generate the clang parsed attribute helpers"), + clEnumValN(GenClangAttrParsedAttrKinds, + "gen-clang-attr-parsed-attr-kinds", + "Generate a clang parsed attribute kinds"), + clEnumValN(GenClangAttrDump, "gen-clang-attr-dump", + "Generate clang attribute dumper"), + clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs", + "Generate Clang diagnostics definitions"), + clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups", + "Generate Clang diagnostic groups"), + clEnumValN(GenClangDiagsIndexName, "gen-clang-diags-index-name", + "Generate Clang diagnostic name index"), + clEnumValN(GenClangCommentNodes, "gen-clang-comment-nodes", + "Generate Clang AST comment nodes"), + clEnumValN(GenClangDeclNodes, "gen-clang-decl-nodes", + "Generate Clang AST declaration nodes"), + clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes", + "Generate Clang AST statement nodes"), + clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers", + "Generate Clang Static Analyzer checkers"), + clEnumValN(GenClangCommentHTMLTags, "gen-clang-comment-html-tags", + "Generate efficient matchers for HTML tag " + "names that are used in documentation comments"), + clEnumValN(GenClangCommentHTMLTagsProperties, + "gen-clang-comment-html-tags-properties", + "Generate efficient matchers for HTML tag " + "properties"), + clEnumValN(GenClangCommentHTMLNamedCharacterReferences, + "gen-clang-comment-html-named-character-references", + "Generate function to translate named character " + "references to UTF-8 sequences"), + clEnumValN(GenClangCommentCommandInfo, "gen-clang-comment-command-info", + "Generate command properties for commands that " + "are used in documentation comments"), + clEnumValN(GenClangCommentCommandList, "gen-clang-comment-command-list", + "Generate list of commands that are used in " + "documentation comments"), + clEnumValN(GenArmNeon, "gen-arm-neon", "Generate arm_neon.h for clang"), + clEnumValN(GenArmNeonSema, "gen-arm-neon-sema", + "Generate ARM NEON sema support for clang"), + clEnumValN(GenArmNeonTest, "gen-arm-neon-test", + "Generate ARM NEON tests for clang"), + clEnumValEnd)); - cl::opt<std::string> - ClangComponent("clang-component", - cl::desc("Only use warnings from specified component"), - cl::value_desc("component"), cl::Hidden); +cl::opt<std::string> +ClangComponent("clang-component", + cl::desc("Only use warnings from specified component"), + cl::value_desc("component"), cl::Hidden); bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { switch (Action) { case GenClangAttrClasses: EmitClangAttrClass(Records, OS); break; - case GenClangAttrExprArgsList: - EmitClangAttrExprArgsList(Records, OS); + case GenClangAttrIdentifierArgList: + EmitClangAttrIdentifierArgList(Records, OS); + break; + case GenClangAttrTypeArgList: + EmitClangAttrTypeArgList(Records, OS); break; case GenClangAttrImpl: EmitClangAttrImpl(Records, OS); @@ -178,6 +180,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenClangAttrParsedAttrList: EmitClangAttrParsedAttrList(Records, OS); break; + case GenClangAttrParsedAttrImpl: + EmitClangAttrParsedAttrImpl(Records, OS); + break; case GenClangAttrParsedAttrKinds: EmitClangAttrParsedAttrKinds(Records, OS); break; @@ -221,12 +226,6 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenClangCommentCommandList: EmitClangCommentCommandList(Records, OS); break; - case GenOptParserDefs: - EmitOptParser(Records, OS, true); - break; - case GenOptParserImpl: - EmitOptParser(Records, OS, false); - break; case GenArmNeon: EmitNeon(Records, OS); break; diff --git a/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h b/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h index 0ff33d7..8904287 100644 --- a/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h +++ b/contrib/llvm/tools/clang/utils/TableGen/TableGenBackends.h @@ -30,7 +30,8 @@ void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS, const std::string &N, const std::string &S); void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS); -void EmitClangAttrExprArgsList(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS); @@ -40,6 +41,7 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS); +void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS); void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS); @@ -61,6 +63,4 @@ void EmitNeon(RecordKeeper &Records, raw_ostream &OS); void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS); void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS); -void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs); - } // end namespace clang |