From d72c9001526228c5a4e0935809cf104a6edf3c93 Mon Sep 17 00:00:00 2001 From: Nate Begeman Date: Sun, 13 Jun 2010 04:47:03 +0000 Subject: Add a helping of comments Add code for generating bits of semachecking git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@105907 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/NeonEmitter.cpp | 113 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 8 deletions(-) diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp index 6c5f86290d..bf5c175335 100644 --- a/utils/TableGen/NeonEmitter.cpp +++ b/utils/TableGen/NeonEmitter.cpp @@ -11,6 +11,15 @@ // a declaration and definition of each function specified by the ARM NEON // compiler interface. See ARM document DUI0348B. // +// Each NEON instruction is implemented in terms of 1 or more functions which +// are suffixed with the element type of the input vectors. Functions may be +// implemented in terms of generic vector operations such as +, *, -, etc. or +// by calling a __builtin_-prefixed function which will be handled by clang's +// CodeGen library. +// +// Additional validation code can be generated by this file when runHeader() is +// called, rather than the normal run() entry point. +// //===----------------------------------------------------------------------===// #include "NeonEmitter.h" @@ -21,6 +30,10 @@ using namespace llvm; +/// ParseTypes - break down a string such as "fQf" into a vector of StringRefs, +/// which each StringRef representing a single type declared in the string. +/// for "fQf" we would end up with 2 StringRefs, "f", and "Qf", representing +/// 2xfloat and 4xfloat respectively. static void ParseTypes(Record *r, std::string &s, SmallVectorImpl &TV) { const char *data = s.data(); @@ -49,6 +62,8 @@ static void ParseTypes(Record *r, std::string &s, } } +/// Widen - Convert a type code into the next wider type. char -> short, +/// short -> int, etc. static char Widen(const char t) { switch (t) { case 'c': @@ -62,6 +77,8 @@ static char Widen(const char t) { return '\0'; } +/// Narrow - Convert a type code into the next smaller type. short -> char, +/// float -> half float, etc. static char Narrow(const char t) { switch (t) { case 's': @@ -77,6 +94,8 @@ static char Narrow(const char t) { return '\0'; } +/// 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; @@ -102,6 +121,8 @@ static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) { return ty[off]; } +/// ModType - Transform a type code and its modifiers based on a mod code. The +/// mod code definitions may be found at the top of arm_neon.td. static char ModType(const char mod, char type, bool &quad, bool &poly, bool &usgn, bool &scal, bool &cnst, bool &pntr) { switch (mod) { @@ -166,8 +187,11 @@ static char ModType(const char mod, char type, bool &quad, bool &poly, return type; } +/// TypeString - for a modifier and type, generate the name of the typedef for +/// that type. If generic is true, emit the generic vector type rather than +/// the public NEON type. QUc -> uint8x8t_t / __neon_uint8x8_t. static std::string TypeString(const char mod, StringRef typestr, - bool ret = false) { + bool generic = false) { bool quad = false; bool poly = false; bool usgn = false; @@ -188,7 +212,7 @@ static std::string TypeString(const char mod, StringRef typestr, SmallString<128> s; - if (ret) + if (generic) s += "__neon_"; if (usgn) @@ -255,6 +279,9 @@ static std::string TypeString(const char mod, StringRef typestr, return s.str(); } +/// TypeString - for a modifier and type, generate the clang BuiltinsARM.def +/// prototype code for the function. See the top of clang's Builtins.def for +/// a description of the type strings. static std::string BuiltinTypeString(const char mod, StringRef typestr, ClassKind ck, bool ret) { bool quad = false; @@ -343,7 +370,9 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr, return quad ? "V16c" : "V8c"; } -// Turn "vst2_lane" into "vst2q_lane_f32", etc. +/// 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. static std::string MangleName(const std::string &name, StringRef typestr, ClassKind ck) { if (name == "vcvt_f32_f16") @@ -623,8 +652,6 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { ret |= 0x08; if (quad) ret |= 0x10; - if (poly) - ret |= 0x20; switch (type) { case 'c': @@ -798,6 +825,8 @@ static std::string GenBuiltinDef(const std::string &name, return s; } +/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h +/// is comprised of type definitions and function declarations. void NeonEmitter::run(raw_ostream &OS) { EmitSourceFileHeader("ARM NEON Header", OS); @@ -813,7 +842,6 @@ void NeonEmitter::run(raw_ostream &OS) { OS << "#include \n\n"; // Emit NEON-specific scalar typedefs. - // FIXME: probably need to do something better for polynomial types. OS << "typedef float float32_t;\n"; OS << "typedef uint8_t poly8_t;\n"; OS << "typedef uint16_t poly16_t;\n"; @@ -918,11 +946,26 @@ void NeonEmitter::run(raw_ostream &OS) { OS << "#endif /* __ARM_NEON_H */\n"; } +/// runHeader - generate one of three different tables which are used by clang +/// to support ARM NEON codegen. By default, this will produce the contents of +/// BuiltinsARM.def's NEON section. You may also enable the genSemaTypes or +/// getSemaRange variables below to generate code that SemaChecking will use to +/// validate the builtin function calls. +/// +/// This is not used as part of the build system currently, but is run manually +/// and the output placed in the appropriate file. void NeonEmitter::runHeader(raw_ostream &OS) { std::vector RV = Records.getAllDerivedDefinitions("Inst"); StringMap EmittedMap; + // Set true to generate the overloaded type checking code for SemaChecking.cpp + bool genSemaTypes = false; + + // Set true to generate the intrinsic range checking code for shift/lane + // immediates for SemaChecking.cpp + bool genSemaRange = true; + for (unsigned i = 0, e = RV.size(); i != e; ++i) { Record *R = RV[i]; @@ -934,18 +977,60 @@ void NeonEmitter::runHeader(raw_ostream &OS) { std::string Proto = R->getValueAsString("Prototype"); std::string Types = R->getValueAsString("Types"); + // 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 have a scalar argument cannot be overloaded, no need to + // check them if we are emitting the type checking code. + if (genSemaTypes && Proto.find('s') != std::string::npos) + continue; + + // Functions which do not have an immediate do not need to have range + // checking code emitted. + if (genSemaRange && Proto.find('i') == std::string::npos) + continue; + SmallVector TypeVec; ParseTypes(R, Types, TypeVec); - + if (R->getSuperClasses().size() < 2) throw TGError(R->getLoc(), "Builtin has no class kind"); ClassKind ck = ClassMap[R->getSuperClasses()[1]]; + int si = -1, qi = -1; + unsigned mask = 0, qmask = 0; for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { + + // Generate the switch case(s) for this builtin for the type validation. + if (genSemaTypes) { + bool quad = false, poly = false, usgn = false; + (void) ClassifyType(TypeVec[ti], quad, poly, usgn); + + if (quad) { + qi = ti; + qmask |= 1 << GetNeonEnum(Proto, TypeVec[ti]); + } else { + si = ti; + mask |= 1 << GetNeonEnum(Proto, TypeVec[ti]); + } + continue; + } + + if (genSemaRange) { + if (Proto.find('s') == std::string::npos) + ck = ClassB; + + OS << "case ARM::BI__builtin_neon_" + << MangleName(name, TypeVec[ti], ck) << "\n"; + continue; + } + + // 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)) continue; @@ -953,5 +1038,17 @@ void NeonEmitter::runHeader(raw_ostream &OS) { EmittedMap[bd] = OpNone; OS << bd << "\n"; } + + if (genSemaTypes) { + if (mask) + OS << "case ARM::BI__builtin_neon_" + << MangleName(name, TypeVec[si], ClassB) + << ": mask = " << "0x" << utohexstr(mask) << "; break;\n"; + if (qmask) + OS << "case ARM::BI__builtin_neon_" + << MangleName(name, TypeVec[qi], ClassB) + << ": mask = " << "0x" << utohexstr(qmask) << "; break;\n"; + continue; + } } } -- cgit v1.2.3