Support using macros for Neon intrinsics implemented without builtins.

Intrinsics implemented with Clang builtins could already be implemented as
either inline functions or macros, but intrinsics implemented directly
(without builtins) could only be inline functions.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120763 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Bob Wilson
2010-12-03 00:34:09 +00:00
parent 5113cdbfff
commit 194aa58066

View File

@ -468,9 +468,14 @@ static std::string GenArgs(const std::string &proto, StringRef typestr) {
s += "("; s += "(";
for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
if (!define) { if (define) {
s += TypeString(proto[i], typestr); // Immediate macro arguments are used directly instead of being assigned
s.push_back(' '); // to local temporaries; prepend an underscore prefix to make their
// names consistent with the local temporaries.
if (proto[i] == 'i')
s += "__";
} else {
s += TypeString(proto[i], typestr) + " __";
} }
s.push_back(arg); s.push_back(arg);
if ((i + 1) < e) if ((i + 1) < e)
@ -481,8 +486,8 @@ static std::string GenArgs(const std::string &proto, StringRef typestr) {
return s; return s;
} }
// Generate the local temporaries used to provide type checking for macro // Macro arguments are not type-checked like inline function arguments, so
// arguments. // assign them to local temporaries to get the right type checking.
static std::string GenMacroLocals(const std::string &proto, StringRef typestr) { static std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
char arg = 'a'; char arg = 'a';
std::string s; std::string s;
@ -544,100 +549,105 @@ static std::string GenOpString(OpKind op, const std::string &proto,
bool quad; bool quad;
unsigned nElts = GetNumElements(typestr, quad); unsigned nElts = GetNumElements(typestr, quad);
// If this builtin takes an immediate argument, we need to #define it rather
// than use a standard declaration, so that SemaChecking can range check
// the immediate passed by the user.
bool define = proto.find('i') != std::string::npos;
std::string ts = TypeString(proto[0], typestr); std::string ts = TypeString(proto[0], typestr);
std::string s; std::string s;
if (op == OpHi || op == OpLo) { if (op == OpHi || op == OpLo) {
s = "union { " + ts + " r; double d; } u; u.d = "; s = "union { " + ts + " r; double d; } u; u.d = ";
} else { } else if (!define) {
s = "return "; s = "return ";
} }
switch(op) { switch(op) {
case OpAdd: case OpAdd:
s += "a + b;"; s += "__a + __b;";
break; break;
case OpSub: case OpSub:
s += "a - b;"; s += "__a - __b;";
break; break;
case OpMulN: case OpMulN:
s += "a * " + Duplicate(nElts, typestr, "b") + ";"; s += "__a * " + Duplicate(nElts, typestr, "__b") + ";";
break; break;
case OpMul: case OpMul:
s += "a * b;"; s += "__a * __b;";
break; break;
case OpMlaN: case OpMlaN:
s += "a + (b * " + Duplicate(nElts, typestr, "c") + ");"; s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");";
break; break;
case OpMla: case OpMla:
s += "a + (b * c);"; s += "__a + (__b * __c);";
break; break;
case OpMlsN: case OpMlsN:
s += "a - (b * " + Duplicate(nElts, typestr, "c") + ");"; s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");";
break; break;
case OpMls: case OpMls:
s += "a - (b * c);"; s += "__a - (__b * __c);";
break; break;
case OpEq: case OpEq:
s += "(" + ts + ")(a == b);"; s += "(" + ts + ")(__a == __b);";
break; break;
case OpGe: case OpGe:
s += "(" + ts + ")(a >= b);"; s += "(" + ts + ")(__a >= __b);";
break; break;
case OpLe: case OpLe:
s += "(" + ts + ")(a <= b);"; s += "(" + ts + ")(__a <= __b);";
break; break;
case OpGt: case OpGt:
s += "(" + ts + ")(a > b);"; s += "(" + ts + ")(__a > __b);";
break; break;
case OpLt: case OpLt:
s += "(" + ts + ")(a < b);"; s += "(" + ts + ")(__a < __b);";
break; break;
case OpNeg: case OpNeg:
s += " -a;"; s += " -__a;";
break; break;
case OpNot: case OpNot:
s += " ~a;"; s += " ~__a;";
break; break;
case OpAnd: case OpAnd:
s += "a & b;"; s += "__a & __b;";
break; break;
case OpOr: case OpOr:
s += "a | b;"; s += "__a | __b;";
break; break;
case OpXor: case OpXor:
s += "a ^ b;"; s += "__a ^ __b;";
break; break;
case OpAndNot: case OpAndNot:
s += "a & ~b;"; s += "__a & ~__b;";
break; break;
case OpOrNot: case OpOrNot:
s += "a | ~b;"; s += "__a | ~__b;";
break; break;
case OpCast: case OpCast:
s += "(" + ts + ")a;"; s += "(" + ts + ")__a;";
break; break;
case OpConcat: case OpConcat:
s += "(" + ts + ")__builtin_shufflevector((int64x1_t)a"; s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a";
s += ", (int64x1_t)b, 0, 1);"; s += ", (int64x1_t)__b, 0, 1);";
break; break;
case OpHi: case OpHi:
s += "(((float64x2_t)a)[1]);"; s += "(((float64x2_t)__a)[1]);";
break; break;
case OpLo: case OpLo:
s += "(((float64x2_t)a)[0]);"; s += "(((float64x2_t)__a)[0]);";
break; break;
case OpDup: case OpDup:
s += Duplicate(nElts, typestr, "a") + ";"; s += Duplicate(nElts, typestr, "__a") + ";";
break; break;
case OpSelect: case OpSelect:
// ((0 & 1) | (~0 & 2)) // ((0 & 1) | (~0 & 2))
s += "(" + ts + ")"; s += "(" + ts + ")";
ts = TypeString(proto[1], typestr); ts = TypeString(proto[1], typestr);
s += "((a & (" + ts + ")b) | "; s += "((__a & (" + ts + ")__b) | ";
s += "(~a & (" + ts + ")c));"; s += "(~__a & (" + ts + ")__c));";
break; break;
case OpRev16: case OpRev16:
s += "__builtin_shufflevector(a, a"; s += "__builtin_shufflevector(__a, __a";
for (unsigned i = 2; i <= nElts; i += 2) for (unsigned i = 2; i <= nElts; i += 2)
for (unsigned j = 0; j != 2; ++j) for (unsigned j = 0; j != 2; ++j)
s += ", " + utostr(i - j - 1); s += ", " + utostr(i - j - 1);
@ -645,7 +655,7 @@ static std::string GenOpString(OpKind op, const std::string &proto,
break; break;
case OpRev32: { case OpRev32: {
unsigned WordElts = nElts >> (1 + (int)quad); unsigned WordElts = nElts >> (1 + (int)quad);
s += "__builtin_shufflevector(a, a"; s += "__builtin_shufflevector(__a, __a";
for (unsigned i = WordElts; i <= nElts; i += WordElts) for (unsigned i = WordElts; i <= nElts; i += WordElts)
for (unsigned j = 0; j != WordElts; ++j) for (unsigned j = 0; j != WordElts; ++j)
s += ", " + utostr(i - j - 1); s += ", " + utostr(i - j - 1);
@ -654,7 +664,7 @@ static std::string GenOpString(OpKind op, const std::string &proto,
} }
case OpRev64: { case OpRev64: {
unsigned DblWordElts = nElts >> (int)quad; unsigned DblWordElts = nElts >> (int)quad;
s += "__builtin_shufflevector(a, a"; s += "__builtin_shufflevector(__a, __a";
for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts) for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts)
for (unsigned j = 0; j != DblWordElts; ++j) for (unsigned j = 0; j != DblWordElts; ++j)
s += ", " + utostr(i - j - 1); s += ", " + utostr(i - j - 1);
@ -665,8 +675,11 @@ static std::string GenOpString(OpKind op, const std::string &proto,
throw "unknown OpKind!"; throw "unknown OpKind!";
break; break;
} }
if (op == OpHi || op == OpLo) if (op == OpHi || op == OpLo) {
s += " return u.r;"; if (!define)
s += " return";
s += " u.r;";
}
return s; return s;
} }
@ -741,11 +754,6 @@ static std::string GenBuiltin(const std::string &name, const std::string &proto,
if (proto.find('s') == std::string::npos) if (proto.find('s') == std::string::npos)
ck = ClassB; ck = ClassB;
// Macro arguments are not type-checked like inline function arguments, so
// assign them to local temporaries to get the right type checking.
if (define)
s += GenMacroLocals(proto, typestr);
if (proto[0] != 'v') { if (proto[0] != 'v') {
std::string ts = TypeString(proto[0], typestr); std::string ts = TypeString(proto[0], typestr);
@ -782,8 +790,7 @@ static std::string GenBuiltin(const std::string &name, const std::string &proto,
for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
std::string args = std::string(&arg, 1); std::string args = std::string(&arg, 1);
// For macros, use the local temporaries instead of the macro arguments. // Use the local temporaries instead of the macro arguments.
if (define && proto[i] != 'i')
args = "__" + args; args = "__" + args;
bool argQuad = false; bool argQuad = false;
@ -970,10 +977,12 @@ void NeonEmitter::run(raw_ostream &OS) {
OS << GenArgs(Proto, TypeVec[ti]); OS << GenArgs(Proto, TypeVec[ti]);
// Definition. // Definition.
if (define) if (define) {
OS << " __extension__ ({ \\\n "; OS << " __extension__ ({ \\\n ";
else OS << GenMacroLocals(Proto, TypeVec[ti]);
} else {
OS << " { \\\n "; OS << " { \\\n ";
}
if (k != OpNone) { if (k != OpNone) {
OS << GenOpString(k, Proto, TypeVec[ti]); OS << GenOpString(k, Proto, TypeVec[ti]);