================ @@ -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()); + if (it != Emitted.end()) { + assert(areRangeChecksCompatable(Checks, it->second) && + "Neon intrinsics with incompatable immediate range checks cannot " + "share a builtin."); + continue; // Ensure this is emitted only once + } - Emitted.insert(Def->getMangledName()); + // Emit builtin's range checks + OS << "case NEON::BI__builtin_neon_" << Def->getMangledName() << ":\n"; + for (const auto &Check : Checks) { + OS << " ImmChecks.push_back(std::make_tuple(" << Check.getImmArgIdx() ---------------- SpencerAbson wrote:
Thanks, done. https://github.com/llvm/llvm-project/pull/100278 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits