mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
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:
parent
114df2f88a
commit
3e4aa8ec69
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user