Add a helping of comments
authorNate Begeman <natebegeman@mac.com>
Sun, 13 Jun 2010 04:47:03 +0000 (04:47 +0000)
committerNate Begeman <natebegeman@mac.com>
Sun, 13 Jun 2010 04:47:03 +0000 (04:47 +0000)
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

index 6c5f86290da01199d45fe280c79bbe8f05cac6c9..bf5c1753356c6553a33299502e9d0ab4270adacb 100644 (file)
 // 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"
 
 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<StringRef> &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 <stdint.h>\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<Record*> RV = Records.getAllDerivedDefinitions("Inst");
 
   StringMap<OpKind> 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<StringRef, 16> 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;
+    }
   }
 }