@@ -309,12 +309,14 @@ instantiateTgt(const std::unordered_map<std::string, std::string> &types,
309309 return instantiated_template;
310310}
311311
312+ // Returns a pair of {iterator, match_result}. The match_result is the value
313+ // returned by match_func for the winning key. When the iterator equals
314+ // container.cend(), match_result is value-initialized (e.g. std::nullopt for
315+ // std::optional).
312316template <class Map , class MatchPred >
313- Map::const_iterator parallel_search (const Map &container,
314- MatchPred &&match_func) {
315- if (container.empty ()) {
316- return container.cend ();
317- }
317+ auto parallel_search (const Map &container, MatchPred &&match_func) {
318+ using MatchResult =
319+ decltype (match_func (std::declval<const typename Map::key_type &>()));
318320
319321 auto tie_breaker = [](const std::string &a, const std::string &b) -> bool {
320322 if (a.size () != b.size ()) {
@@ -324,13 +326,35 @@ Map::const_iterator parallel_search(const Map &container,
324326 return a < b; // Lexicographically
325327 };
326328
329+ std::optional<typename Map::key_type> hit_key;
330+ MatchResult hit_match;
331+
332+ if (container.empty ()) {
333+ return std::make_pair (container.cend (), std::move (hit_match));
334+ }
335+
336+ // Serial fast-path: avoids thread-pool creation overhead for small maps.
337+ constexpr size_t kSerialThreshold = 16 ;
338+ if (container.size () <= kSerialThreshold ) {
339+ for (auto it = container.cbegin (); it != container.cend (); ++it) {
340+ auto m = match_func (it->first );
341+ if (!m)
342+ continue ;
343+ if (!hit_key || tie_breaker (it->first , *hit_key)) {
344+ hit_key = it->first ;
345+ hit_match = std::move (m);
346+ }
347+ }
348+ return std::make_pair (hit_key ? container.find (*hit_key) : container.cend (),
349+ std::move (hit_match));
350+ }
351+
327352 const unsigned hw = std::max (1u , std::thread::hardware_concurrency ());
328353 const unsigned nthreads =
329354 std::min<unsigned >(hw, std::max<size_t >(1 , container.bucket_count ()));
330355
331356 std::atomic<size_t > next_bucket{0 };
332357 std::mutex hit_mtx;
333- std::optional<typename Map::key_type> hit_key;
334358
335359 auto worker = [&](unsigned ) {
336360 while (true ) {
@@ -340,13 +364,14 @@ Map::const_iterator parallel_search(const Map &container,
340364 }
341365
342366 for (auto it = container.cbegin (b); it != container.cend (b); ++it) {
343- if (!match_func (it->first )) {
367+ auto m = match_func (it->first );
368+ if (!m)
344369 continue ;
345- }
346370
347371 std::scoped_lock lk (hit_mtx);
348372 if (!hit_key || tie_breaker (it->first , *hit_key)) {
349373 hit_key = it->first ;
374+ hit_match = std::move (m);
350375 }
351376 }
352377 }
@@ -360,12 +385,13 @@ Map::const_iterator parallel_search(const Map &container,
360385 pool.wait ();
361386 }
362387
363- return hit_key ? container.find (*hit_key) : container.cend ();
388+ return std::make_pair (hit_key ? container.find (*hit_key) : container.cend (),
389+ std::move (hit_match));
364390}
365391
366392decltype (exprs_)::const_iterator search (const clang::Expr *expr) {
367393 auto qualified_name = ToString (expr);
368- auto result = parallel_search (exprs_, [&](const std::string &tpl) {
394+ auto [ result, match] = parallel_search (exprs_, [&](const std::string &tpl) {
369395 return matchTemplate (tpl, qualified_name);
370396 });
371397 llvm::errs () << " search expr " << qualified_name << " , result:\n " ;
@@ -379,7 +405,7 @@ decltype(exprs_)::const_iterator search(const clang::Expr *expr) {
379405
380406decltype (types_)::const_iterator search (clang::QualType qual_type) {
381407 auto type = ToString (qual_type);
382- auto result = parallel_search (
408+ auto [ result, match] = parallel_search (
383409 types_, [&](const std::string &tpl) { return matchTemplate (tpl, type); });
384410 llvm::errs () << " search type " << type << " , result: "
385411 << ((result == types_.end ()) ? " None"
@@ -528,22 +554,23 @@ clang::QualType normalizeQualType(clang::QualType qual_type) {
528554}
529555
530556std::string mapTypeStringRecursive (const std::string &cpp_type) {
531- auto rule = parallel_search (types_, [&](const std::string &tpl) {
557+ auto [ rule, match] = parallel_search (types_, [&](const std::string &tpl) {
532558 return matchTemplate (tpl, cpp_type);
533559 });
534560 if (rule == types_.end ()) {
535561 llvm::errs () << " cpp_type: " << cpp_type << ' \n ' ;
536562 assert (0 && " Type is not present in types_" );
537563 }
538- auto subs = matchTemplate (rule-> first , cpp_type ).value ();
564+ auto subs = std::move (match ).value ();
539565 for (auto &kv : subs) {
540566 kv.second = mapTypeStringRecursive (kv.second );
541567 }
542568 return instantiateTgt (subs, rule->second .type_info .type );
543569}
544570
545571std::string normalizeTranslationRule (std::string rule) {
546- const std::array<std::pair<std::regex, std::string>, 2 > normalization_rules{{
572+ static const std::array<std::pair<std::regex, std::string>, 2 >
573+ normalization_rules{{
547574 // Detach pointer from double reference. Useful for matching translation
548575 // rules.
549576 {std::regex (R"( \*\&\&)" ), " * &&" },
@@ -601,20 +628,26 @@ std::string MapFunctionName(const clang::FunctionDecl *decl) {
601628
602629std::string InstantiateTemplate (const clang::Expr *expr,
603630 const std::string &text) {
604- auto it = search (expr);
631+ auto qualified_name = ToString (expr);
632+ auto [it, match] = parallel_search (exprs_, [&](const std::string &tpl) {
633+ return matchTemplate (tpl, qualified_name);
634+ });
605635 if (it == exprs_.end ()) {
606636 return text;
607637 }
608- auto types_map = matchTemplate (it-> first , ToString (expr) ).value ();
638+ auto types_map = std::move (match ).value ();
609639 for (auto &kv : types_map) {
610640 kv.second = mapTypeStringRecursive (kv.second );
611641 }
612642 return instantiateTgt (types_map, text);
613643}
614644
615645std::string Map (clang::QualType qual_type) {
616- if (auto it = search (qual_type); it != types_.end ()) {
617- auto types_map = matchTemplate (it->first , ToString (qual_type)).value ();
646+ auto type_str = ToString (qual_type);
647+ auto [it, match] = parallel_search (
648+ types_, [&](const std::string &tpl) { return matchTemplate (tpl, type_str); });
649+ if (it != types_.end ()) {
650+ auto types_map = std::move (match).value ();
618651 for (auto &kv : types_map) {
619652 kv.second = mapTypeStringRecursive (kv.second );
620653 }
@@ -656,12 +689,20 @@ const TranslationRule::TypeInfo &GetParamInfo(const clang::Expr *expr,
656689}
657690
658691std::string GetParamType (const clang::Expr *expr, unsigned index) {
659- auto &info = GetParamInfo (expr, index);
660- auto types_map = matchTemplate (search (expr)->first , ToString (expr)).value ();
692+ auto qualified_name = ToString (expr);
693+ auto [it, match] = parallel_search (exprs_, [&](const std::string &tpl) {
694+ return matchTemplate (tpl, qualified_name);
695+ });
696+ assert (it != exprs_.end () && " expression must have a translation rule" );
697+ auto name = " a" + std::to_string (index);
698+ auto name_it = it->second .params .find (name);
699+ assert (name_it != it->second .params .end () &&
700+ " placeholder arg must have a corresponding param type in IR" );
701+ auto types_map = std::move (match).value ();
661702 for (auto &kv : types_map) {
662703 kv.second = mapTypeStringRecursive (kv.second );
663704 }
664- return instantiateTgt (types_map, info .type );
705+ return instantiateTgt (types_map, name_it-> second .type );
665706}
666707
667708bool ParamIsPointer (const clang::Expr *expr, unsigned index) {
0 commit comments