@@ -380,15 +380,23 @@ using Base.Experimental: @opaque
380
380
f_oc_getfield (x) = (@opaque ()-> x)()
381
381
@test fully_eliminated (f_oc_getfield, Tuple{Int})
382
382
383
- # check if `x` is a statically-resolved call of a function whose name is `sym`
384
- isinvoke (@nospecialize (x), sym:: Symbol ) = isinvoke (x, mi-> mi. def. name=== sym)
385
- function isinvoke (@nospecialize (x), pred)
386
- if Meta. isexpr (x, :invoke )
387
- return pred (x. args[1 ]:: Core.MethodInstance )
383
+ import Core. Compiler: argextype
384
+ const EMPTY_SPTYPES = Core. Compiler. EMPTY_SLOTTYPES
385
+
386
+ code_typed1 (args... ; kwargs... ) = first (only (code_typed (args... ; kwargs... ))):: Core.CodeInfo
387
+ get_code (args... ; kwargs... ) = code_typed1 (args... ; kwargs... ). code
388
+
389
+ # check if `x` is a dynamic call of a given function
390
+ function iscall ((src, f):: Tuple{Core.CodeInfo,Function} , @nospecialize (x))
391
+ return iscall (x) do @nospecialize x
392
+ argextype (x, src, EMPTY_SPTYPES) === typeof (f)
388
393
end
389
- return false
390
394
end
391
- code_typed1 (args... ; kwargs... ) = (first (only (code_typed (args... ; kwargs... ))):: Core.CodeInfo ). code
395
+ iscall (pred, @nospecialize (x)) = Meta. isexpr (x, :call ) && pred (x. args[1 ])
396
+
397
+ # check if `x` is a statically-resolved call of a function whose name is `sym`
398
+ isinvoke (sym:: Symbol , @nospecialize (x)) = isinvoke (mi-> mi. def. name=== sym, x)
399
+ isinvoke (pred, @nospecialize (x)) = Meta. isexpr (x, :invoke ) && pred (x. args[1 ]:: Core.MethodInstance )
392
400
393
401
@testset " @inline/@noinline annotation before definition" begin
394
402
M = Module ()
@@ -413,25 +421,25 @@ code_typed1(args...; kwargs...) = (first(only(code_typed(args...; kwargs...)))::
413
421
def_noinline_noconflict (x) = _def_noinline_noconflict (x)
414
422
end
415
423
416
- let code = code_typed1 (M. def_inline, (Int,))
417
- @test all (code) do x
418
- ! isinvoke (x, :_def_inline )
424
+ let code = get_code (M. def_inline, (Int,))
425
+ @test all (code) do @nospecialize x
426
+ ! isinvoke (:_def_inline , x )
419
427
end
420
428
end
421
- let code = code_typed1 (M. def_noinline, (Int,))
422
- @test any (code) do x
423
- isinvoke (x, :_def_noinline )
429
+ let code = get_code (M. def_noinline, (Int,))
430
+ @test any (code) do @nospecialize x
431
+ isinvoke (:_def_noinline , x )
424
432
end
425
433
end
426
434
# test that they don't conflict with other "before-definition" macros
427
- let code = code_typed1 (M. def_inline_noconflict, (Int,))
428
- @test all (code) do x
429
- ! isinvoke (x, :_def_inline_noconflict )
435
+ let code = get_code (M. def_inline_noconflict, (Int,))
436
+ @test all (code) do @nospecialize x
437
+ ! isinvoke (:_def_inline_noconflict , x )
430
438
end
431
439
end
432
- let code = code_typed1 (M. def_noinline_noconflict, (Int,))
433
- @test any (code) do x
434
- isinvoke (x, :_def_noinline_noconflict )
440
+ let code = get_code (M. def_noinline_noconflict, (Int,))
441
+ @test any (code) do @nospecialize x
442
+ isinvoke (:_def_noinline_noconflict , x )
435
443
end
436
444
end
437
445
end
@@ -470,29 +478,33 @@ end
470
478
end
471
479
end
472
480
473
- let code = code_typed1 (M. body_inline, (Int,))
474
- @test all (code) do x
475
- ! isinvoke (x, :_body_inline )
481
+ let code = get_code (M. body_inline, (Int,))
482
+ @test all (code) do @nospecialize x
483
+ ! isinvoke (:_body_inline , x )
476
484
end
477
485
end
478
- let code = code_typed1 (M. body_noinline, (Int,))
479
- @test any (code) do x
480
- isinvoke (x, :_body_noinline )
486
+ let code = get_code (M. body_noinline, (Int,))
487
+ @test any (code) do @nospecialize x
488
+ isinvoke (:_body_noinline , x )
481
489
end
482
490
end
483
491
# test annotations for `do` blocks
484
- let code = code_typed1 (M. do_inline, (Int,))
492
+ let code = get_code (M. do_inline, (Int,))
485
493
# what we test here is that both `simple_caller` and the anonymous function that the
486
494
# `do` block creates should inlined away, and as a result there is only the unresolved call
487
- @test all (code) do x
488
- ! isinvoke (x, :simple_caller ) &&
489
- ! isinvoke (x, mi-> startswith (string (mi. def. name), ' #' ))
495
+ @test all (code) do @nospecialize x
496
+ ! isinvoke (:simple_caller , x) &&
497
+ ! isinvoke (x) do mi
498
+ startswith (string (mi. def. name), ' #' )
499
+ end
490
500
end
491
501
end
492
- let code = code_typed1 (M. do_noinline, (Int,))
502
+ let code = get_code (M. do_noinline, (Int,))
493
503
# the anonymous function that the `do` block created shouldn't be inlined here
494
- @test any (code) do x
495
- isinvoke (x, mi-> startswith (string (mi. def. name), ' #' ))
504
+ @test any (code) do @nospecialize x
505
+ isinvoke (x) do mi
506
+ startswith (string (mi. def. name), ' #' )
507
+ end
496
508
end
497
509
end
498
510
end
@@ -520,14 +532,14 @@ end
520
532
# test callsite annotations for constant-prop'ed calls
521
533
522
534
@noinline Base. @constprop :aggressive noinlined_constprop_explicit (a) = a+ g
523
- force_inline_constprop_explicit () = @inline noinlined_constprop_explicit (0 )
535
+ force_inline_constprop_explicit () = @inline noinlined_constprop_explicit (0 )
524
536
Base. @constprop :aggressive noinlined_constprop_implicit (a) = a+ g
525
- force_inline_constprop_implicit () = @inline noinlined_constprop_implicit (0 )
537
+ force_inline_constprop_implicit () = @inline noinlined_constprop_implicit (0 )
526
538
527
539
@inline Base. @constprop :aggressive inlined_constprop_explicit (a) = a+ g
528
- force_noinline_constprop_explicit () = @noinline inlined_constprop_explicit (0 )
540
+ force_noinline_constprop_explicit () = @noinline inlined_constprop_explicit (0 )
529
541
@inline Base. @constprop :aggressive inlined_constprop_implicit (a) = a+ g
530
- force_noinline_constprop_implicit () = @noinline inlined_constprop_implicit (0 )
542
+ force_noinline_constprop_implicit () = @noinline inlined_constprop_implicit (0 )
531
543
532
544
@noinline notinlined (a) = a
533
545
function nested (a0, b0)
@@ -539,51 +551,75 @@ end
539
551
end
540
552
end
541
553
542
- let code = code_typed1 (M. force_inline_explicit, (Int,))
543
- @test all (x-> ! isinvoke (x, :noinlined_explicit ), code)
554
+ let code = get_code (M. force_inline_explicit, (Int,))
555
+ @test all (code) do @nospecialize x
556
+ ! isinvoke (:noinlined_explicit , x)
557
+ end
544
558
end
545
- let code = code_typed1 (M. force_inline_block_explicit, (Int,))
546
- @test all (code) do x
547
- ! isinvoke (x, :noinlined_explicit ) &&
548
- ! isinvoke (x, :(+ ))
559
+ let code = get_code (M. force_inline_block_explicit, (Int,))
560
+ @test all (code) do @nospecialize x
561
+ ! isinvoke (:noinlined_explicit , x ) &&
562
+ ! isinvoke (:(+ ), x )
549
563
end
550
564
end
551
- let code = code_typed1 (M. force_inline_implicit, (Int,))
552
- @test all (x-> ! isinvoke (x, :noinlined_implicit ), code)
565
+ let code = get_code (M. force_inline_implicit, (Int,))
566
+ @test all (code) do @nospecialize x
567
+ ! isinvoke (:noinlined_implicit , x)
568
+ end
553
569
end
554
- let code = code_typed1 (M. force_inline_block_implicit, (Int,))
555
- @test all (x-> ! isinvoke (x, :noinlined_explicit ), code)
570
+ let code = get_code (M. force_inline_block_implicit, (Int,))
571
+ @test all (code) do @nospecialize x
572
+ ! isinvoke (:noinlined_explicit , x)
573
+ end
556
574
end
557
575
558
- let code = code_typed1 (M. force_noinline_explicit, (Int,))
559
- @test any (x-> isinvoke (x, :inlined_explicit ), code)
576
+ let code = get_code (M. force_noinline_explicit, (Int,))
577
+ @test any (code) do @nospecialize x
578
+ isinvoke (:inlined_explicit , x)
579
+ end
560
580
end
561
- let code = code_typed1 (M. force_noinline_block_explicit, (Int,))
562
- @test count (x-> isinvoke (x, :inlined_explicit ), code) == 2
581
+ let code = get_code (M. force_noinline_block_explicit, (Int,))
582
+ @test count (code) do @nospecialize x
583
+ isinvoke (:inlined_explicit , x)
584
+ end == 2
563
585
end
564
- let code = code_typed1 (M. force_noinline_implicit, (Int,))
565
- @test any (x-> isinvoke (x, :inlined_implicit ), code)
586
+ let code = get_code (M. force_noinline_implicit, (Int,))
587
+ @test any (code) do @nospecialize x
588
+ isinvoke (:inlined_implicit , x)
589
+ end
566
590
end
567
- let code = code_typed1 (M. force_noinline_block_implicit, (Int,))
568
- @test count (x-> isinvoke (x, :inlined_implicit ), code) == 2
591
+ let code = get_code (M. force_noinline_block_implicit, (Int,))
592
+ @test count (code) do @nospecialize x
593
+ isinvoke (:inlined_implicit , x)
594
+ end == 2
569
595
end
570
596
571
- let code = code_typed1 (M. force_inline_constprop_explicit)
572
- @test all (x-> ! isinvoke (x, :noinlined_constprop_explicit ), code)
597
+ let code = get_code (M. force_inline_constprop_explicit)
598
+ @test all (code) do @nospecialize x
599
+ ! isinvoke (:noinlined_constprop_explicit , x)
600
+ end
573
601
end
574
- let code = code_typed1 (M. force_inline_constprop_implicit)
575
- @test all (x-> ! isinvoke (x, :noinlined_constprop_implicit ), code)
602
+ let code = get_code (M. force_inline_constprop_implicit)
603
+ @test all (code) do @nospecialize x
604
+ ! isinvoke (:noinlined_constprop_implicit , x)
605
+ end
576
606
end
577
607
578
- let code = code_typed1 (M. force_noinline_constprop_explicit)
579
- @test any (x-> isinvoke (x, :inlined_constprop_explicit ), code)
608
+ let code = get_code (M. force_noinline_constprop_explicit)
609
+ @test any (code) do @nospecialize x
610
+ isinvoke (:inlined_constprop_explicit , x)
611
+ end
580
612
end
581
- let code = code_typed1 (M. force_noinline_constprop_implicit)
582
- @test any (x-> isinvoke (x, :inlined_constprop_implicit ), code)
613
+ let code = get_code (M. force_noinline_constprop_implicit)
614
+ @test any (code) do @nospecialize x
615
+ isinvoke (:inlined_constprop_implicit , x)
616
+ end
583
617
end
584
618
585
- let code = code_typed1 (M. nested, (Int,Int))
586
- @test count (x-> isinvoke (x, :notinlined ), code) == 1
619
+ let code = get_code (M. nested, (Int,Int))
620
+ @test count (code) do @nospecialize x
621
+ isinvoke (:notinlined , x)
622
+ end == 1
587
623
end
588
624
end
589
625
@@ -604,10 +640,12 @@ let code = @eval Module() begin
604
640
end
605
641
end
606
642
607
- $ code_typed1 (setter, (Vector{Foo},))
643
+ $ get_code (setter, (Vector{Foo},))
608
644
end
609
645
610
- @test ! any (x-> isinvoke (x, :setproperty! ), code)
646
+ @test ! any (code) do @nospecialize x
647
+ isinvoke (:setproperty! , x)
648
+ end
611
649
end
612
650
613
651
# Issue #41299 - inlining deletes error check in :>
@@ -624,10 +662,12 @@ end
624
662
@noinline f42078 (a) = sum (sincos (a))
625
663
let
626
664
ninlined = let
627
- code = code_typed1 ((Int,)) do a
665
+ code = get_code ((Int,)) do a
628
666
@inline f42078 (a)
629
667
end
630
- @test all (x-> ! isinvoke (x, :f42078 ), code)
668
+ @test all (code) do @nospecialize x
669
+ ! isinvoke (:f42078 , x)
670
+ end
631
671
length (code)
632
672
end
633
673
@@ -643,10 +683,12 @@ let
643
683
end
644
684
645
685
let # inference should re-infer `f42078(::Int)` and we should get the same code
646
- code = code_typed1 ((Int,)) do a
686
+ code = get_code ((Int,)) do a
647
687
@inline f42078 (a)
648
688
end
649
- @test all (x-> ! isinvoke (x, :f42078 ), code)
689
+ @test all (code) do @nospecialize x
690
+ ! isinvoke (:f42078 , x)
691
+ end
650
692
@test ninlined == length (code)
651
693
end
652
694
end
@@ -688,21 +730,16 @@ mutable struct X42754
688
730
a:: Union{Nothing, Int}
689
731
b:: Symbol
690
732
end
691
- let code = code_typed1 ((X42754, Union{Nothing,Int})) do x, a
733
+ let src = code_typed1 ((X42754, Union{Nothing,Int})) do x, a
692
734
# this `setproperty` call would be union-split and constant-prop will happen for
693
735
# each signature: inlining would fail if we don't use constant-prop'ed source
694
736
# since the approximate inlining cost of `convert(fieldtype(X, sym), a)` would
695
737
# end up very high if we don't propagate `sym::Const(:a)`
696
738
x. a = a
697
739
x
698
740
end
699
- @test all (code) do @nospecialize (x)
700
- isinvoke (x, :setproperty! ) && return false
701
- if Meta. isexpr (x, :call )
702
- f = x. args[1 ]
703
- isa (f, GlobalRef) && f. name === :setproperty! && return false
704
- end
705
- return true
741
+ @test all (src. code) do @nospecialize x
742
+ ! (isinvoke (:setproperty! , x) || iscall ((src, setproperty!), x))
706
743
end
707
744
end
708
745
@@ -713,32 +750,22 @@ import Base: @constprop
713
750
@constprop :none @inline test_single_nondispatchtuple (@nospecialize (t)) =
714
751
isa (t, DataType) && t. name === Type. body. name
715
752
let
716
- code = code_typed1 ((Any,)) do x
753
+ src = code_typed1 ((Any,)) do x
717
754
test_single_nondispatchtuple (x)
718
755
end
719
- @test all (code) do @nospecialize (x)
720
- isinvoke (x, :test_single_nondispatchtuple ) && return false
721
- if Meta. isexpr (x, :call )
722
- f = x. args[1 ]
723
- isa (f, GlobalRef) && f. name === :test_single_nondispatchtuple && return false
724
- end
725
- return true
756
+ @test all (src. code) do @nospecialize x
757
+ ! (isinvoke (:test_single_nondispatchtuple , x) || iscall ((src, test_single_nondispatchtuple), x))
726
758
end
727
759
end
728
760
729
761
@constprop :aggressive @inline test_single_nondispatchtuple (c, @nospecialize (t)) =
730
762
c && isa (t, DataType) && t. name === Type. body. name
731
763
let
732
- code = code_typed1 ((Any,)) do x
764
+ src = code_typed1 ((Any,)) do x
733
765
test_single_nondispatchtuple (true , x)
734
766
end
735
- @test all (code) do @nospecialize (x)
736
- isinvoke (x, :test_single_nondispatchtuple ) && return false
737
- if Meta. isexpr (x, :call )
738
- f = x. args[1 ]
739
- isa (f, GlobalRef) && f. name === :test_single_nondispatchtuple && return false
740
- end
741
- return true
767
+ @test all (src. code) do @nospecialize (x)
768
+ ! (isinvoke (:test_single_nondispatchtuple , x) || iscall ((src, test_single_nondispatchtuple), x))
742
769
end
743
770
end
744
771
0 commit comments