diff options
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 |