Add a Neon intrinsic test generator.

This is still a WIP.  It's already good enough to expose a few bugs, though.

llvm-svn: 121868
This commit is contained in:
Bob Wilson 2010-12-15 16:58:45 +00:00
parent 276f1ca897
commit 9168a4f1c2
3 changed files with 115 additions and 1 deletions

View File

@ -18,7 +18,8 @@
// CodeGen library.
//
// Additional validation code can be generated by this file when runHeader() is
// called, rather than the normal run() entry point.
// called, rather than the normal run() entry point. A complete set of tests
// for Neon intrinsics can be generated by calling the runTests() entry point.
//
//===----------------------------------------------------------------------===//
@ -1423,3 +1424,107 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
}
OS << "#endif\n\n";
}
/// GenTest - Write out a test for the intrinsic specified by the name and
/// type strings, including the embedded patterns for FileCheck to match.
static std::string GenTest(const std::string &name,
const std::string &proto,
StringRef outTypeStr, StringRef inTypeStr,
bool isShift) {
assert(!proto.empty() && "");
std::string s;
// Function name with type suffix
std::string mangledName = MangleName(name, outTypeStr, ClassS);
if (outTypeStr != inTypeStr) {
// If the input type is different (e.g., for vreinterpret), append a suffix
// for the input type. String off a "Q" (quad) prefix so that MangleName
// does not insert another "q" in the name.
unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
}
// Emit the FileCheck patterns.
s += "// CHECK: test_" + mangledName + "\n";
// s += "// CHECK: \n"; // FIXME: + expected instruction opcode.
// Emit the start of the test function.
s += TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
char arg = 'a';
std::string comma;
for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
// Do not create arguments for values that must be immediate constants.
if (proto[i] == 'i')
continue;
s += comma + TypeString(proto[i], inTypeStr) + " ";
s.push_back(arg);
comma = ", ";
}
s += ") { \\\n ";
if (proto[0] != 'v')
s += "return ";
s += mangledName + "(";
arg = 'a';
for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
if (proto[i] == 'i') {
// For immediate operands, test the maximum value.
if (isShift)
s += "1"; // FIXME
else
// The immediate generally refers to a lane in the preceding argument.
s += utostr(RangeFromType(proto[i-1], inTypeStr));
} else {
s.push_back(arg);
}
if ((i + 1) < e)
s += ", ";
}
s += ");\n}\n\n";
return s;
}
/// runTests - Write out a complete set of tests for all of the Neon
/// intrinsics.
void NeonEmitter::runTests(raw_ostream &OS) {
OS <<
"// RUN: %clang_cc1 -triple thumbv7-apple-darwin \\\n"
"// RUN: -target-cpu cortex-a8 -ffreestanding -S -o - %s | FileCheck %s\n"
"\n"
"#include <arm_neon.h>\n"
"\n";
std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
Record *R = RV[i];
std::string name = R->getValueAsString("Name");
std::string Proto = R->getValueAsString("Prototype");
std::string Types = R->getValueAsString("Types");
bool isShift = R->getValueAsBit("isShift");
SmallVector<StringRef, 16> TypeVec;
ParseTypes(R, Types, TypeVec);
OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
if (kind == OpReinterpret) {
bool outQuad = false;
bool dummy = false;
(void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
for (unsigned srcti = 0, srcte = TypeVec.size();
srcti != srcte; ++srcti) {
bool inQuad = false;
(void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
if (srcti == ti || inQuad != outQuad)
continue;
OS << GenTest(name, Proto, TypeVec[ti], TypeVec[srcti], isShift);
}
} else {
OS << GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift);
}
}
OS << "\n";
}
}

View File

@ -168,6 +168,9 @@ namespace llvm {
// runHeader - Emit all the __builtin prototypes used in arm_neon.h
void runHeader(raw_ostream &o);
// runTests - Emit tests for all the Neon intrinsics.
void runTests(raw_ostream &o);
private:
void emitIntrinsic(raw_ostream &OS, Record *R);
};

View File

@ -75,6 +75,7 @@ enum ActionType {
GenEDInfo,
GenArmNeon,
GenArmNeonSema,
GenArmNeonTest,
PrintEnums
};
@ -147,6 +148,8 @@ namespace {
"Generate arm_neon.h for clang"),
clEnumValN(GenArmNeonSema, "gen-arm-neon-sema",
"Generate ARM NEON sema support for clang"),
clEnumValN(GenArmNeonTest, "gen-arm-neon-test",
"Generate ARM NEON tests for clang"),
clEnumValN(PrintEnums, "print-enums",
"Print enum values for a class"),
clEnumValEnd));
@ -330,6 +333,9 @@ int main(int argc, char **argv) {
case GenArmNeonSema:
NeonEmitter(Records).runHeader(Out.os());
break;
case GenArmNeonTest:
NeonEmitter(Records).runTests(Out.os());
break;
case PrintEnums:
{
std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class);