[clang] [llvm] [Clang][AArch64] Add customisable immediate range checking to NEON (PR #100278)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 2 08:44:41 PDT 2024
================
@@ -2142,85 +2178,58 @@ void NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
OS << "#endif\n\n";
}
-void NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,
- SmallVectorImpl<Intrinsic *> &Defs) {
- OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
+inline bool
+NeonEmitter::areRangeChecksCompatable(const ArrayRef<ImmCheck> ChecksA,
+ const ArrayRef<ImmCheck> ChecksB) {
+ // If multiple intrinsics map to the same builtin, we must ensure that the
+ // intended range checks performed in SemaArm.cpp do not contradict each
+ // other, as these are emitted once per-buitlin.
+ //
+ // The arguments to be checked and type of each check to be performed must be
+ // the same. The element types may differ as they will be resolved
+ // per-intrinsic as overloaded types by SemaArm.cpp, though the vector sizes
+ // are not and so must be the same.
+ bool compat =
+ std::equal(ChecksA.begin(), ChecksA.end(), ChecksB.begin(), ChecksB.end(),
+ [](const auto A, const auto B) {
+ return A.getImmArgIdx() == B.getImmArgIdx() &&
+ A.getKind() == B.getKind() &&
+ A.getVecSizeInBits() == B.getVecSizeInBits();
+ });
+
+ return compat;
+}
- std::set<std::string> Emitted;
+void NeonEmitter::genIntrinsicRangeCheckCode(
+ raw_ostream &OS, SmallVectorImpl<Intrinsic *> &Defs) {
+ std::unordered_map<std::string, ArrayRef<ImmCheck>> Emitted;
- for (auto *Def : Defs) {
- if (Def->hasBody())
- continue;
- // Functions which do not have an immediate do not need to have range
- // checking code emitted.
- if (!Def->hasImmediate())
- continue;
- if (Emitted.find(Def->getMangledName()) != Emitted.end())
+ OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
+ for (auto &Def : Defs) {
+ // If the Def has a body (operation DAGs), it is not a __builtin_neon_
+ if (Def->hasBody() || !Def->hasImmediate())
continue;
- std::string LowerBound, UpperBound;
-
- Record *R = Def->getRecord();
- if (R->getValueAsBit("isVXAR")) {
- //VXAR takes an immediate in the range [0, 63]
- LowerBound = "0";
- UpperBound = "63";
- } else if (R->getValueAsBit("isVCVT_N")) {
- // VCVT between floating- and fixed-point values takes an immediate
- // in the range [1, 32) for f32 or [1, 64) for f64 or [1, 16) for f16.
- LowerBound = "1";
- if (Def->getBaseType().getElementSizeInBits() == 16 ||
- Def->getName().find('h') != std::string::npos)
- // VCVTh operating on FP16 intrinsics in range [1, 16)
- UpperBound = "15";
- else if (Def->getBaseType().getElementSizeInBits() == 32)
- UpperBound = "31";
- else
- UpperBound = "63";
- } else if (R->getValueAsBit("isScalarShift")) {
- // Right shifts have an 'r' in the name, left shifts do not. Convert
- // instructions have the same bounds and right shifts.
- if (Def->getName().find('r') != std::string::npos ||
- Def->getName().find("cvt") != std::string::npos)
- LowerBound = "1";
-
- UpperBound = utostr(Def->getReturnType().getElementSizeInBits() - 1);
- } else if (R->getValueAsBit("isShift")) {
- // Builtins which are overloaded by type will need to have their upper
- // bound computed at Sema time based on the type constant.
-
- // Right shifts have an 'r' in the name, left shifts do not.
- if (Def->getName().find('r') != std::string::npos)
- LowerBound = "1";
- UpperBound = "RFT(TV, true)";
- } else if (Def->getClassKind(true) == ClassB) {
- // ClassB intrinsics have a type (and hence lane number) that is only
- // known at runtime.
- if (R->getValueAsBit("isLaneQ"))
- UpperBound = "RFT(TV, false, true)";
- else
- UpperBound = "RFT(TV, false, false)";
- } else {
- // The immediate generally refers to a lane in the preceding argument.
- assert(Def->getImmediateIdx() > 0);
- Type T = Def->getParamType(Def->getImmediateIdx() - 1);
- UpperBound = utostr(T.getNumElements() - 1);
- }
+ // Sorted by immediate argument index
+ ArrayRef<ImmCheck> Checks = Def->getImmChecks();
- // Calculate the index of the immediate that should be range checked.
- unsigned Idx = Def->getNumParams();
- if (Def->hasImmediate())
- Idx = Def->getGeneratedParamIdx(Def->getImmediateIdx());
-
- OS << "case NEON::BI__builtin_neon_" << Def->getMangledName() << ": "
- << "i = " << Idx << ";";
- if (!LowerBound.empty())
- OS << " l = " << LowerBound << ";";
- if (!UpperBound.empty())
- OS << " u = " << UpperBound << ";";
- OS << " break;\n";
+ const auto it = Emitted.find(Def->getMangledName());
----------------
SpencerAbson wrote:
I agree that this would be cleaner, but it's convenient to have the iterator returned by `find` and do the lookup just once in the case that this succeeds.
https://github.com/llvm/llvm-project/pull/100278
More information about the cfe-commits
mailing list