mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
Add a helping of comments
Add code for generating bits of semachecking llvm-svn: 105907
This commit is contained in:
parent
1f31d12e8f
commit
955d383e5b
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user