summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorNate Begeman <natebegeman@mac.com>2010-06-13 04:47:03 +0000
committerNate Begeman <natebegeman@mac.com>2010-06-13 04:47:03 +0000
commitd72c9001526228c5a4e0935809cf104a6edf3c93 (patch)
treeefee73d7c4e647c715405617de02fb946a9d69b9 /utils
parent21d238fdbacd2be880712202eab03c7e42fe769c (diff)
downloadllvm-d72c9001526228c5a4e0935809cf104a6edf3c93.tar.gz
llvm-d72c9001526228c5a4e0935809cf104a6edf3c93.tar.bz2
llvm-d72c9001526228c5a4e0935809cf104a6edf3c93.tar.xz
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
Diffstat (limited to 'utils')
-rw-r--r--utils/TableGen/NeonEmitter.cpp113
1 files 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<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;
+ }
}
}