Modify tablegen to support generating all NEON code used by clang at once.
[oota-llvm.git] / utils / TableGen / NeonEmitter.cpp
index bf5c1753356c6553a33299502e9d0ab4270adacb..689db653cb54099eed5b89eb12017e40c5647990 100644 (file)
@@ -526,17 +526,17 @@ static std::string GenOpString(OpKind op, const std::string &proto,
     s += a + " - " + b;
     break;
   case OpMulN:
-    b = Duplicate(nElts << quad, typestr, "b");
+    b = Duplicate(nElts << (int)quad, typestr, "b");
   case OpMul:
     s += a + " * " + b;
     break;
   case OpMlaN:
-    c = Duplicate(nElts << quad, typestr, "c");
+    c = Duplicate(nElts << (int)quad, typestr, "c");
   case OpMla:
     s += a + " + ( " + b + " * " + c + " )";
     break;
   case OpMlsN:
-    c = Duplicate(nElts << quad, typestr, "c");
+    c = Duplicate(nElts << (int)quad, typestr, "c");
   case OpMls:
     s += a + " - ( " + b + " * " + c + " )";
     break;
@@ -590,7 +590,7 @@ static std::string GenOpString(OpKind op, const std::string &proto,
     s += "(__neon_int64x1_t)(((__neon_int64x2_t)" + a + ")[0])";
     break;
   case OpDup:
-    s += Duplicate(nElts << quad, typestr, a);
+    s += Duplicate(nElts << (int)quad, typestr, a);
     break;
   case OpSelect:
     // ((0 & 1) | (~0 & 2))
@@ -600,7 +600,7 @@ static std::string GenOpString(OpKind op, const std::string &proto,
     break;
   case OpRev16:
     s += "__builtin_shufflevector(" + a + ", " + a;
-    for (unsigned i = 2; i <= nElts << quad; i += 2)
+    for (unsigned i = 2; i <= nElts << (int)quad; i += 2)
       for (unsigned j = 0; j != 2; ++j)
         s += ", " + utostr(i - j - 1);
     s += ")";
@@ -608,14 +608,14 @@ static std::string GenOpString(OpKind op, const std::string &proto,
   case OpRev32:
     nElts >>= 1;
     s += "__builtin_shufflevector(" + a + ", " + a;
-    for (unsigned i = nElts; i <= nElts << (1 + quad); i += nElts)
+    for (unsigned i = nElts; i <= nElts << (1 + (int)quad); i += nElts)
       for (unsigned j = 0; j != nElts; ++j)
         s += ", " + utostr(i - j - 1);
     s += ")";
     break;
   case OpRev64:
     s += "__builtin_shufflevector(" + a + ", " + a;
-    for (unsigned i = nElts; i <= nElts << quad; i += nElts)
+    for (unsigned i = nElts; i <= nElts << (int)quad; i += nElts)
       for (unsigned j = 0; j != nElts; ++j)
         s += ", " + utostr(i - j - 1);
     s += ")";
@@ -946,37 +946,88 @@ 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.
+static unsigned RangeFromType(StringRef typestr) {
+  // base type to get the type string for.
+  bool quad = false, dummy = false;
+  char type = ClassifyType(typestr, quad, dummy, dummy);
+  
+  switch (type) {
+    case 'c':
+      return (8 << (int)quad) - 1;
+    case 'h':
+    case 's':
+      return (4 << (int)quad) - 1;
+    case 'f':
+    case 'i':
+      return (2 << (int)quad) - 1;
+    case 'l':
+      return (1 << (int)quad) - 1;
+    default:
+      throw "unhandled type!";
+      break;
+  }
+}
+
+/// 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 immedate arguments.
 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;
-  
+  // Generate BuiltinsARM.def for NEON
+  OS << "#ifdef GET_NEON_BUILTINS\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 Proto = R->getValueAsString("Prototype");
+    
+    // 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");
+    SmallVector<StringRef, 16> TypeVec;
+    ParseTypes(R, Types, TypeVec);
+    
+    if (R->getSuperClasses().size() < 2)
+      throw TGError(R->getLoc(), "Builtin has no class kind");
     
     std::string name = LowercaseString(R->getName());
+    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
+    
+    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))
+        continue;
+      
+      EmittedMap[bd] = OpNone;
+      OS << bd << "\n";
+    }
+  }
+  OS << "#endif\n\n";
+  
+  // Generate the overloaded type checking code for SemaChecking.cpp
+  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()];
+    if (k != OpNone)
+      continue;
+    
     std::string Proto = R->getValueAsString("Prototype");
     std::string Types = R->getValueAsString("Types");
-
+    std::string name = LowercaseString(R->getName());
+    
     // 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)
@@ -984,12 +1035,62 @@ 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 (genSemaTypes && Proto.find('s') != std::string::npos)
+    if (Proto.find('s') != 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");
+    
+    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.
+      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]);
+      }
+    }
+    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";
+  }
+  OS << "#endif\n\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 = LowercaseString(R->getName());
+    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 do not have an immediate do not need to have range
     // checking code emitted.
-    if (genSemaRange && Proto.find('i') == std::string::npos)
+    if (Proto.find('i') == std::string::npos)
       continue;
     
     SmallVector<StringRef, 16> TypeVec;
@@ -1000,55 +1101,43 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
     
     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) {
+      std::string namestr, shiftstr, rangestr;
       
-      // 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]);
+      // Builtins which are overloaded by type will need to have their upper
+      // bound computed at Sema time based on the type constant.
+      if (Proto.find('s') == std::string::npos) {
+        ck = ClassB;
+        if (R->getValueAsBit("isShift")) {
+          shiftstr = ", true";
+          
+          // Right shifts have an 'r' in the name, left shifts do not.
+          if (name.find('r') != std::string::npos)
+            rangestr = "l = 1; ";
         }
-        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;
+        rangestr += "u = RFT(TV" + shiftstr + ")";
+      } else {
+        rangestr = "u = " + utostr(RangeFromType(TypeVec[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))
+      // Make sure cases appear only once.
+      namestr = MangleName(name, TypeVec[ti], ck);
+      if (EmittedMap.count(namestr))
         continue;
+      EmittedMap[namestr] = OpNone;
       
-      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;
+      unsigned immidx = 0;
+      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";
     }
   }
+  OS << "#endif\n\n";
 }