llvm_unreachable("Invalid NeonTypeFlag!");
}
-bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
- CallExpr *TheCall) {
-
+bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
llvm::APSInt Result;
-
uint64_t mask = 0;
unsigned TV = 0;
int PtrArgNum = -1;
bool HasConstPtr = false;
switch (BuiltinID) {
-#define GET_NEON_AARCH64_OVERLOAD_CHECK
+#define GET_NEON_OVERLOAD_CHECK
#include "clang/Basic/arm_neon.inc"
-#undef GET_NEON_AARCH64_OVERLOAD_CHECK
+#undef GET_NEON_OVERLOAD_CHECK
}
// For NEON intrinsics which are overloaded on vector element type, validate
// the immediate which specifies which variant to emit.
- unsigned ImmArg = TheCall->getNumArgs() - 1;
+ unsigned ImmArg = TheCall->getNumArgs()-1;
if (mask) {
if (SemaBuiltinConstantArg(TheCall, ImmArg, Result))
return true;
TV = Result.getLimitedValue(64);
if ((TV > 63) || (mask & (1ULL << TV)) == 0)
return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code)
- << TheCall->getArg(ImmArg)->getSourceRange();
+ << TheCall->getArg(ImmArg)->getSourceRange();
}
if (PtrArgNum >= 0) {
Arg = ICE->getSubExpr();
ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg);
QualType RHSTy = RHS.get()->getType();
- QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context, true);
+
+ bool IsAArch64 =
+ Context.getTargetInfo().getTriple().getArch() == llvm::Triple::aarch64;
+ QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context, IsAArch64);
if (HasConstPtr)
EltTy = EltTy.withConst();
QualType LHSTy = Context.getPointerType(EltTy);
switch (BuiltinID) {
default:
return false;
-#define GET_NEON_AARCH64_IMMEDIATE_CHECK
+#define GET_NEON_IMMEDIATE_CHECK
#include "clang/Basic/arm_neon.inc"
-#undef GET_NEON_AARCH64_IMMEDIATE_CHECK
+#undef GET_NEON_IMMEDIATE_CHECK
}
;
return false;
}
+bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
+ CallExpr *TheCall) {
+ if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
+ return true;
+
+ return false;
+}
+
bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall) {
assert((BuiltinID == ARM::BI__builtin_arm_ldrex ||
BuiltinID == ARM::BI__builtin_arm_strex) &&
return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall);
}
- uint64_t mask = 0;
- unsigned TV = 0;
- int PtrArgNum = -1;
- bool HasConstPtr = false;
- switch (BuiltinID) {
-#define GET_NEON_OVERLOAD_CHECK
-#include "clang/Basic/arm_neon.inc"
-#undef GET_NEON_OVERLOAD_CHECK
- }
-
- // For NEON intrinsics which are overloaded on vector element type, validate
- // the immediate which specifies which variant to emit.
- unsigned ImmArg = TheCall->getNumArgs()-1;
- if (mask) {
- if (SemaBuiltinConstantArg(TheCall, ImmArg, Result))
- return true;
-
- TV = Result.getLimitedValue(64);
- if ((TV > 63) || (mask & (1ULL << TV)) == 0)
- return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code)
- << TheCall->getArg(ImmArg)->getSourceRange();
- }
-
- if (PtrArgNum >= 0) {
- // Check that pointer arguments have the specified type.
- Expr *Arg = TheCall->getArg(PtrArgNum);
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg))
- Arg = ICE->getSubExpr();
- ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg);
- QualType RHSTy = RHS.get()->getType();
- QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context, false);
- if (HasConstPtr)
- EltTy = EltTy.withConst();
- QualType LHSTy = Context.getPointerType(EltTy);
- AssignConvertType ConvTy;
- ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS);
- if (RHS.isInvalid())
- return true;
- if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), LHSTy, RHSTy,
- RHS.get(), AA_Assigning))
- return true;
- }
+ if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
+ return true;
// For NEON intrinsics which take an immediate value as part of the
// instruction, range check them here.
case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break;
case ARM::BI__builtin_arm_dmb:
case ARM::BI__builtin_arm_dsb: l = 0; u = 15; break;
-#define GET_NEON_IMMEDIATE_CHECK
-#include "clang/Basic/arm_neon.inc"
-#undef GET_NEON_IMMEDIATE_CHECK
};
// We can't check the value of a dependent argument.
void emitIntrinsic(raw_ostream &OS, Record *R,
StringMap<ClassKind> &EmittedMap);
void genBuiltinsDef(raw_ostream &OS);
- void genOverloadTypeCheckCode(raw_ostream &OS,
- StringMap<ClassKind> &A64IntrinsicMap,
- bool isA64TypeCheck);
- void genIntrinsicRangeCheckCode(raw_ostream &OS,
- StringMap<ClassKind> &A64IntrinsicMap,
- bool isA64RangeCheck);
+ void genOverloadTypeCheckCode(raw_ostream &OS);
+ void genIntrinsicRangeCheckCode(raw_ostream &OS);
void genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
bool isA64TestGen);
};
/// Generate the ARM and AArch64 intrinsic range checking code for
/// shift/lane immediates, checking for unique declarations.
void
-NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,
- StringMap<ClassKind> &A64IntrinsicMap,
- bool isA64RangeCheck) {
+NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS) {
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
StringMap<OpKind> EmittedMap;
// Generate the intrinsic range checking code for shift/lane immediates.
- if (isA64RangeCheck)
- OS << "#ifdef GET_NEON_AARCH64_IMMEDIATE_CHECK\n";
- else
- OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
+ OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
Record *R = RV[i];
if (!ProtoHasScalar(Proto))
ck = ClassB;
- // Do not include AArch64 range checks if not generating code for AArch64.
- bool isA64 = R->getValueAsBit("isA64");
- if (!isA64RangeCheck && isA64)
- continue;
-
- // Include ARM range checks in AArch64 but only if ARM intrinsics are not
- // redefined by AArch64 to handle new types.
- if (isA64RangeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
- ClassKind &A64CK = A64IntrinsicMap[Rename];
- if (A64CK == ck && ck != ClassNone)
- continue;
- }
-
for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
std::string namestr, shiftstr, rangestr;
/// Generate the ARM and AArch64 overloaded type checking code for
/// SemaChecking.cpp, checking for unique builtin declarations.
void
-NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
- StringMap<ClassKind> &A64IntrinsicMap,
- bool isA64TypeCheck) {
+NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS) {
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
// Generate the overloaded type checking code for SemaChecking.cpp
- if (isA64TypeCheck)
- OS << "#ifdef GET_NEON_AARCH64_OVERLOAD_CHECK\n";
- else
- OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
+ OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
+
+ // We record each overload check line before emitting because subsequent Inst
+ // definitions may extend the number of permitted types (i.e. augment the
+ // Mask). Use std::map to avoid sorting the table by hash number.
+ struct OverloadInfo {
+ uint64_t Mask;
+ int PtrArgNum;
+ bool HasConstPtr;
+ };
+ std::map<std::string, OverloadInfo> OverloadMap;
+ typedef std::map<std::string, OverloadInfo>::iterator OverloadIterator;
for (unsigned i = 0, e = RV.size(); i != e; ++i) {
Record *R = RV[i];
if (R->getSuperClasses().size() < 2)
PrintFatalError(R->getLoc(), "Builtin has no class kind");
- // Do not include AArch64 type checks if not generating code for AArch64.
- bool isA64 = R->getValueAsBit("isA64");
- if (!isA64TypeCheck && isA64)
- continue;
-
- // Include ARM type check in AArch64 but only if ARM intrinsics
- // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
- // redefined in AArch64 to handle an additional 2 x f64 type.
- ClassKind ck = ClassMap[R->getSuperClasses()[1]];
- if (isA64TypeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
- ClassKind &A64CK = A64IntrinsicMap[Rename];
- if (A64CK == ck && ck != ClassNone)
- continue;
- }
-
int si = -1, qi = -1;
uint64_t mask = 0, qmask = 0;
for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
}
if (mask) {
- OS << "case NEON::BI__builtin_neon_";
- OS << MangleName(name, TypeVec[si], ClassB) << ": mask = "
- << "0x" << utohexstr(mask) << "ULL";
- if (PtrArgNum >= 0)
- OS << "; PtrArgNum = " << PtrArgNum;
- if (HasConstPtr)
- OS << "; HasConstPtr = true";
- OS << "; break;\n";
+ std::pair<OverloadIterator, bool> I = OverloadMap.insert(std::make_pair(
+ MangleName(name, TypeVec[si], ClassB), OverloadInfo()));
+ OverloadInfo &Record = I.first->second;
+ if (!I.second)
+ assert(Record.PtrArgNum == PtrArgNum &&
+ Record.HasConstPtr == HasConstPtr);
+ Record.Mask |= mask;
+ Record.PtrArgNum = PtrArgNum;
+ Record.HasConstPtr = HasConstPtr;
}
if (qmask) {
- OS << "case NEON::BI__builtin_neon_";
- OS << MangleName(name, TypeVec[qi], ClassB) << ": mask = "
- << "0x" << utohexstr(qmask) << "ULL";
- if (PtrArgNum >= 0)
- OS << "; PtrArgNum = " << PtrArgNum;
- if (HasConstPtr)
- OS << "; HasConstPtr = true";
- OS << "; break;\n";
+ std::pair<OverloadIterator, bool> I = OverloadMap.insert(std::make_pair(
+ MangleName(name, TypeVec[qi], ClassB), OverloadInfo()));
+ OverloadInfo &Record = I.first->second;
+ if (!I.second)
+ assert(Record.PtrArgNum == PtrArgNum &&
+ Record.HasConstPtr == HasConstPtr);
+ Record.Mask |= qmask;
+ Record.PtrArgNum = PtrArgNum;
+ Record.HasConstPtr = HasConstPtr;
}
}
+
+ for (OverloadIterator I = OverloadMap.begin(), E = OverloadMap.end(); I != E;
+ ++I) {
+ OverloadInfo &BuiltinOverloads = I->second;
+ OS << "case NEON::BI__builtin_neon_" << I->first << ": ";
+ OS << "mask = " << "0x" << utohexstr(BuiltinOverloads.Mask) << "ULL";
+ if (BuiltinOverloads.PtrArgNum >= 0)
+ OS << "; PtrArgNum = " << BuiltinOverloads.PtrArgNum;
+ if (BuiltinOverloads.HasConstPtr)
+ OS << "; HasConstPtr = true";
+ OS << "; break;\n";
+ }
+
OS << "#endif\n\n";
}
void NeonEmitter::runHeader(raw_ostream &OS) {
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
- // build a map of AArch64 intriniscs to be used in uniqueness checks.
- StringMap<ClassKind> A64IntrinsicMap;
- for (unsigned i = 0, e = RV.size(); i != e; ++i) {
- Record *R = RV[i];
-
- bool isA64 = R->getValueAsBit("isA64");
- if (!isA64)
- continue;
-
- ClassKind CK = ClassNone;
- if (R->getSuperClasses().size() >= 2)
- CK = ClassMap[R->getSuperClasses()[1]];
-
- std::string Name = R->getValueAsString("Name");
- std::string Proto = R->getValueAsString("Prototype");
- std::string Rename = Name + "@" + Proto;
- if (A64IntrinsicMap.count(Rename))
- continue;
- A64IntrinsicMap[Rename] = CK;
- }
-
// Generate shared BuiltinsXXX.def
genBuiltinsDef(OS);
// Generate ARM overloaded type checking code for SemaChecking.cpp
- genOverloadTypeCheckCode(OS, A64IntrinsicMap, false);
-
- // Generate AArch64 overloaded type checking code for SemaChecking.cpp
- genOverloadTypeCheckCode(OS, A64IntrinsicMap, true);
+ genOverloadTypeCheckCode(OS);
// Generate ARM range checking code for shift/lane immediates.
- genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, false);
-
- // Generate the AArch64 range checking code for shift/lane immediates.
- genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, true);
+ genIntrinsicRangeCheckCode(OS);
}
/// GenTest - Write out a test for the intrinsic specified by the name and