Skip to content

Commit b24c944

Browse files
author
Howard Hinnant
committed
One more small optimization: Where possible, for loops that do a search and then try to break out of the loop early, eliminate the attempt to break out of the loop after the last search. And with that, I'm declaring __dynamic_cast done. Though if anyone sees any problems, has suggestions for improvements, or wants to contribute some test cases, that is certainly welcome feedback.
llvm-svn: 148246
1 parent 7c4dcf4 commit b24c944

File tree

3 files changed

+91
-82
lines changed

3 files changed

+91
-82
lines changed

libcxxabi/src/private_typeinfo.cpp

Lines changed: 84 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -282,12 +282,8 @@ __class_type_info::process_static_type_below_dst(__dynamic_cast_info* info,
282282
const void* current_ptr,
283283
int path_below) const
284284
{
285-
// Record that we found a static_type
286-
info->found_any_static_type = true; // TODO: Consider removing, no one is currently listening
287285
if (current_ptr == info->static_ptr)
288286
{
289-
// Record that we found (static_ptr, static_type)
290-
info->found_our_static_ptr = true; // TODO: Consider removing, no one is currently listening
291287
// Record the most public path from (dynamic_ptr, dynamic_type) to
292288
// (static_ptr, static_type)
293289
if (info->path_dynamic_ptr_to_static_ptr != public_path)
@@ -424,59 +420,64 @@ __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
424420
{
425421
// This is not a static_type and not a dst_type.
426422
const Iter e = __base_info + __base_count;
427-
if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1)
423+
Iter p = __base_info;
424+
p->search_below_dst(info, current_ptr, path_below);
425+
if (++p < e)
428426
{
429-
// If there are multiple paths to a base above from here, or if
430-
// a dst_type pointing to (static_ptr, static_type) has been found,
431-
// then there is no way to break out of this loop early unless
432-
// something below detects the search is done.
433-
for (Iter p = __base_info; p < e; ++p)
427+
if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1)
434428
{
435-
p->search_below_dst(info, current_ptr, path_below);
436-
if (info->search_done)
437-
break;
429+
// If there are multiple paths to a base above from here, or if
430+
// a dst_type pointing to (static_ptr, static_type) has been found,
431+
// then there is no way to break out of this loop early unless
432+
// something below detects the search is done.
433+
do
434+
{
435+
if (info->search_done)
436+
break;
437+
p->search_below_dst(info, current_ptr, path_below);
438+
} while (++p < e);
438439
}
439-
}
440-
else if (__flags & __non_diamond_repeat_mask)
441-
{
442-
// There are not multiple paths to any base class from here and a
443-
// dst_type pointing to (static_ptr, static_type) has not yet been
444-
// found.
445-
for (Iter p = __base_info; p < e; ++p)
440+
else if (__flags & __non_diamond_repeat_mask)
446441
{
447-
p->search_below_dst(info, current_ptr, path_below);
448-
if (info->search_done)
449-
break;
450-
// If we just found a dst_type with a public path to (static_ptr, static_type),
451-
// then the only reason to continue the search is to make sure
452-
// no other dst_type points to (static_ptr, static_type).
453-
// If !diamond, then we don't need to search here.
454-
if (info->number_to_static_ptr == 1 &&
455-
info->path_dst_ptr_to_static_ptr == public_path)
456-
break;
442+
// There are not multiple paths to any base class from here and a
443+
// dst_type pointing to (static_ptr, static_type) has not yet been
444+
// found.
445+
do
446+
{
447+
if (info->search_done)
448+
break;
449+
// If we just found a dst_type with a public path to (static_ptr, static_type),
450+
// then the only reason to continue the search is to make sure
451+
// no other dst_type points to (static_ptr, static_type).
452+
// If !diamond, then we don't need to search here.
453+
if (info->number_to_static_ptr == 1 &&
454+
info->path_dst_ptr_to_static_ptr == public_path)
455+
break;
456+
p->search_below_dst(info, current_ptr, path_below);
457+
} while (++p < e);
457458
}
458-
}
459-
else
460-
{
461-
// There are no repeated types above this node.
462-
// There are no nodes with multiple parents above this node.
463-
// no dst_type has been found to (static_ptr, static_type)
464-
for (Iter p = __base_info; p < e; ++p)
459+
else
465460
{
466-
p->search_below_dst(info, current_ptr, path_below);
467-
if (info->search_done)
468-
break;
469-
// If we just found a dst_type with a public path to (static_ptr, static_type),
470-
// then the only reason to continue the search is to make sure sure
471-
// no other dst_type points to (static_ptr, static_type).
472-
// If !diamond, then we don't need to search here.
473-
// if we just found a dst_type with a private path to (static_ptr, static_type),
474-
// then we're only looking for a public path to (static_ptr, static_type)
475-
// and to check for other dst_types.
476-
// If !diamond & !repeat, then there is not a pointer to (static_ptr, static_type)
477-
// and not a dst_type under here.
478-
if (info->number_to_static_ptr == 1)
479-
break;
461+
// There are no repeated types above this node.
462+
// There are no nodes with multiple parents above this node.
463+
// no dst_type has been found to (static_ptr, static_type)
464+
do
465+
{
466+
if (info->search_done)
467+
break;
468+
// If we just found a dst_type with a public path to (static_ptr, static_type),
469+
// then the only reason to continue the search is to make sure sure
470+
// no other dst_type points to (static_ptr, static_type).
471+
// If !diamond, then we don't need to search here.
472+
// if we just found a dst_type with a private path to (static_ptr, static_type),
473+
// then we're only looking for a public path to (static_ptr, static_type)
474+
// and to check for other dst_types.
475+
// If !diamond & !repeat, then there is not a pointer to (static_ptr, static_type)
476+
// and not a dst_type under here.
477+
if (info->number_to_static_ptr == 1)
478+
break;
479+
p->search_below_dst(info, current_ptr, path_below);
480+
} while (++p < e);
480481
}
481482
}
482483
}
@@ -640,33 +641,41 @@ __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
640641
// 3. We can prove that there is no public path to (static_ptr, static_type)
641642
// above here.
642643
const Iter e = __base_info + __base_count;
643-
for (Iter p = __base_info; p < e; ++p)
644+
Iter p = __base_info;
645+
// Zero out found flags
646+
info->found_our_static_ptr = false;
647+
info->found_any_static_type = false;
648+
p->search_above_dst(info, dst_ptr, current_ptr, path_below);
649+
if (++p < e)
644650
{
645-
// Zero out found flags
646-
info->found_our_static_ptr = false;
647-
info->found_any_static_type = false;
648-
p->search_above_dst(info, dst_ptr, current_ptr, path_below);
649-
if (info->search_done)
650-
break;
651-
if (info->found_our_static_ptr)
651+
do
652652
{
653-
// If we found what we're looking for, stop looking above.
654-
if (info->path_dst_ptr_to_static_ptr == public_path)
655-
break;
656-
// We found a private path to (static_ptr, static_type)
657-
// If there is no diamond then there is only one path
658-
// to (static_ptr, static_type) from here and we just found it.
659-
if (!(__flags & __diamond_shaped_mask))
660-
break;
661-
}
662-
else if (info->found_any_static_type)
663-
{
664-
// If we found a static_type that isn't the one we're looking
665-
// for, and if there are no repeated types above here,
666-
// then stop looking.
667-
if (!(__flags & __non_diamond_repeat_mask))
653+
if (info->search_done)
668654
break;
669-
}
655+
if (info->found_our_static_ptr)
656+
{
657+
// If we found what we're looking for, stop looking above.
658+
if (info->path_dst_ptr_to_static_ptr == public_path)
659+
break;
660+
// We found a private path to (static_ptr, static_type)
661+
// If there is no diamond then there is only one path
662+
// to (static_ptr, static_type) from here and we just found it.
663+
if (!(__flags & __diamond_shaped_mask))
664+
break;
665+
}
666+
else if (info->found_any_static_type)
667+
{
668+
// If we found a static_type that isn't the one we're looking
669+
// for, and if there are no repeated types above here,
670+
// then stop looking.
671+
if (!(__flags & __non_diamond_repeat_mask))
672+
break;
673+
}
674+
// Zero out found flags
675+
info->found_our_static_ptr = false;
676+
info->found_any_static_type = false;
677+
p->search_above_dst(info, dst_ptr, current_ptr, path_below);
678+
} while (++p < e);
670679
}
671680
// Restore flags
672681
info->found_our_static_ptr = found_our_static_ptr;

libcxxabi/test/dynamic_cast_stress.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ int main()
7373
Timing results I'm seeing (median of 3 microseconds):
7474
7575
libc++abi gcc's dynamic_cast
76-
B<Width/2, Depth> -O3 50.694 93.190 libc++abi 84% faster
77-
B<Width/2, Depth> -Os 55.235 94.103 libc++abi 70% faster
78-
A<Width, Depth> -O3 14.895 33.134 libc++abi 122% faster
79-
A<Width, Depth> -Os 16.515 31.553 libc++abi 91% faster
76+
B<Width/2, Depth> -O3 48.334 93.190 libc++abi 93% faster
77+
B<Width/2, Depth> -Os 58.535 94.103 libc++abi 61% faster
78+
A<Width, Depth> -O3 11.515 33.134 libc++abi 188% faster
79+
A<Width, Depth> -Os 12.631 31.553 libc++abi 150% faster
8080
8181
*/

libcxxabi/www/spec.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -824,9 +824,9 @@
824824
</p>
825825
</blockquote>
826826
</td>
827-
<td></td>
828-
<td></td>
829-
<td></td>
827+
<td>&#10003;</td>
828+
<td>&#10003;</td>
829+
<td>&#10003;</td>
830830
</tr>
831831

832832
</table>

0 commit comments

Comments
 (0)