Peephole optimise adjacent pairs of nextstate ops.
authorNicholas Clark <nick@ccl4.org>
Fri, 27 Aug 2010 20:48:55 +0000 (21:48 +0100)
committerNicholas Clark <nick@ccl4.org>
Fri, 27 Aug 2010 20:48:55 +0000 (21:48 +0100)
Previously, in code such as

    use constant DEBUG=>0;

    sub GAK {
        warn if DEBUG;
        print "stuff\n";
    }

the ops for C<warn if DEBUG;> would be folded to a null op (ex-const), but
the nextstate op would remain, resulting in a runtime op dispatch of nextstate,
nextstate, ...

The execution of a sequence of nexstate ops is indistinguishable from just the
last nextstate op, so teach the peephole optimiser to eliminate the first of a
pair of nextstate ops. (Except where the first carries a label, as labels
mustn't be eliminated by the optimiser, and label usage isn't conclusively
known at compile time.)

ext/B/t/optree_samples.t
ext/B/t/optree_specials.t
op.c
t/op/goto.t

index 6003ab2..2a78972 100644 (file)
@@ -278,57 +278,57 @@ checkOptree ( name        => '-basic sub { print "foo $_" foreach (1..10) }',
              bcopts    => '-basic',
              strip_open_hints => 1,
              expect    => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
-# h  <1> leavesub[1 ref] K/REFC,1 ->(end)
-# -     <@> lineseq KP ->h
+# g  <1> leavesub[1 ref] K/REFC,1 ->(end)
+# -     <@> lineseq KP ->g
 # 1        <;> nextstate(main 445 optree.t:167) v:>,<,% ->2
-# 2        <;> nextstate(main 445 optree.t:167) v:>,<,% ->3
-# g        <2> leaveloop K/2 ->h
-# 7           <{> enteriter(next->d last->g redo->8) lKS/8 ->e
-# -              <0> ex-pushmark s ->3
-# -              <1> ex-list lK ->6
-# 3                 <0> pushmark s ->4
-# 4                 <$> const[IV 1] s ->5
-# 5                 <$> const[IV 10] s ->6
-# 6              <#> gv[*_] s ->7
-# -           <1> null K/1 ->g
-# f              <|> and(other->8) K/1 ->g
-# e                 <0> iter s ->f
+# -        <0> null v ->-
+# f        <2> leaveloop K/2 ->g
+# 6           <{> enteriter(next->c last->f redo->7) lKS/8 ->d
+# -              <0> ex-pushmark s ->2
+# -              <1> ex-list lK ->5
+# 2                 <0> pushmark s ->3
+# 3                 <$> const[IV 1] s ->4
+# 4                 <$> const[IV 10] s ->5
+# 5              <#> gv[*_] s ->6
+# -           <1> null K/1 ->f
+# e              <|> and(other->7) K/1 ->f
+# d                 <0> iter s ->e
 # -                 <@> lineseq sK ->-
-# c                    <@> print vK ->d
-# 8                       <0> pushmark s ->9
-# -                       <1> ex-stringify sK/1 ->c
-# -                          <0> ex-pushmark s ->9
-# b                          <2> concat[t2] sK/2 ->c
-# 9                             <$> const[PV "foo "] s ->a
-# -                             <1> ex-rv2sv sK/1 ->b
-# a                                <#> gvsv[*_] s ->b
-# d                    <0> unstack s ->e
+# b                    <@> print vK ->c
+# 7                       <0> pushmark s ->8
+# -                       <1> ex-stringify sK/1 ->b
+# -                          <0> ex-pushmark s ->8
+# a                          <2> concat[t2] sK/2 ->b
+# 8                             <$> const[PV "foo "] s ->9
+# -                             <1> ex-rv2sv sK/1 ->a
+# 9                                <#> gvsv[*_] s ->a
+# c                    <0> unstack s ->d
 EOT_EOT
-# h  <1> leavesub[1 ref] K/REFC,1 ->(end)
-# -     <@> lineseq KP ->h
+# g  <1> leavesub[1 ref] K/REFC,1 ->(end)
+# -     <@> lineseq KP ->g
 # 1        <;> nextstate(main 446 optree_samples.t:192) v:>,<,% ->2
-# 2        <;> nextstate(main 446 optree_samples.t:192) v:>,<,% ->3
-# g        <2> leaveloop K/2 ->h
-# 7           <{> enteriter(next->d last->g redo->8) lKS/8 ->e
-# -              <0> ex-pushmark s ->3
-# -              <1> ex-list lK ->6
-# 3                 <0> pushmark s ->4
-# 4                 <$> const(IV 1) s ->5
-# 5                 <$> const(IV 10) s ->6
-# 6              <$> gv(*_) s ->7
-# -           <1> null K/1 ->g
-# f              <|> and(other->8) K/1 ->g
-# e                 <0> iter s ->f
+# -        <0> null v ->-
+# f        <2> leaveloop K/2 ->g
+# 6           <{> enteriter(next->c last->f redo->7) lKS/8 ->d
+# -              <0> ex-pushmark s ->2
+# -              <1> ex-list lK ->5
+# 2                 <0> pushmark s ->3
+# 3                 <$> const(IV 1) s ->4
+# 4                 <$> const(IV 10) s ->5
+# 5              <$> gv(*_) s ->6
+# -           <1> null K/1 ->f
+# e              <|> and(other->7) K/1 ->f
+# d                 <0> iter s ->e
 # -                 <@> lineseq sK ->-
-# c                    <@> print vK ->d
-# 8                       <0> pushmark s ->9
-# -                       <1> ex-stringify sK/1 ->c
-# -                          <0> ex-pushmark s ->9
-# b                          <2> concat[t1] sK/2 ->c
-# 9                             <$> const(PV "foo ") s ->a
-# -                             <1> ex-rv2sv sK/1 ->b
-# a                                <$> gvsv(*_) s ->b
-# d                    <0> unstack s ->e
+# b                    <@> print vK ->c
+# 7                       <0> pushmark s ->8
+# -                       <1> ex-stringify sK/1 ->b
+# -                          <0> ex-pushmark s ->8
+# a                          <2> concat[t1] sK/2 ->b
+# 8                             <$> const(PV "foo ") s ->9
+# -                             <1> ex-rv2sv sK/1 ->a
+# 9                                <$> gvsv(*_) s ->a
+# c                    <0> unstack s ->d
 EONT_EONT
 
 checkOptree ( name     => '-exec -e foreach (1..10) {print qq{foo $_}}',
@@ -383,42 +383,40 @@ checkOptree ( name        => '-exec sub { print "foo $_" foreach (1..10) }',
              strip_open_hints => 1,
              expect    => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
 # 1  <;> nextstate(main 445 optree.t:167) v:>,<,%
-# 2  <;> nextstate(main 445 optree.t:167) v:>,<,%
-# 3  <0> pushmark s
-# 4  <$> const[IV 1] s
-# 5  <$> const[IV 10] s
-# 6  <#> gv[*_] s
-# 7  <{> enteriter(next->d last->g redo->8) lKS/8
-# e  <0> iter s
-# f  <|> and(other->8) K/1
-# 8      <0> pushmark s
-# 9      <$> const[PV "foo "] s
-# a      <#> gvsv[*_] s
-# b      <2> concat[t2] sK/2
-# c      <@> print vK
-# d      <0> unstack s
-#            goto e
-# g  <2> leaveloop K/2
-# h  <1> leavesub[1 ref] K/REFC,1
+# 2  <0> pushmark s
+# 3  <$> const[IV 1] s
+# 4  <$> const[IV 10] s
+# 5  <#> gv[*_] s
+# 6  <{> enteriter(next->c last->f redo->7) lKS/8
+# d  <0> iter s
+# e  <|> and(other->7) K/1
+# 7      <0> pushmark s
+# 8      <$> const[PV "foo "] s
+# 9      <#> gvsv[*_] s
+# a      <2> concat[t2] sK/2
+# b      <@> print vK
+# c      <0> unstack s
+#            goto d
+# f  <2> leaveloop K/2
+# g  <1> leavesub[1 ref] K/REFC,1
 EOT_EOT
 # 1  <;> nextstate(main 447 optree_samples.t:252) v:>,<,%
-# 2  <;> nextstate(main 447 optree_samples.t:252) v:>,<,%
-# 3  <0> pushmark s
-# 4  <$> const(IV 1) s
-# 5  <$> const(IV 10) s
-# 6  <$> gv(*_) s
-# 7  <{> enteriter(next->d last->g redo->8) lKS/8
-# e  <0> iter s
-# f  <|> and(other->8) K/1
-# 8      <0> pushmark s
-# 9      <$> const(PV "foo ") s
-# a      <$> gvsv(*_) s
-# b      <2> concat[t1] sK/2
-# c      <@> print vK
-# d      <0> unstack s
-#            goto e
-# g  <2> leaveloop K/2
-# h  <1> leavesub[1 ref] K/REFC,1
+# 2  <0> pushmark s
+# 3  <$> const(IV 1) s
+# 4  <$> const(IV 10) s
+# 5  <$> gv(*_) s
+# 6  <{> enteriter(next->c last->f redo->7) lKS/8
+# d  <0> iter s
+# e  <|> and(other->7) K/1
+# 7      <0> pushmark s
+# 8      <$> const(PV "foo ") s
+# 9      <$> gvsv(*_) s
+# a      <2> concat[t1] sK/2
+# b      <@> print vK
+# c      <0> unstack s
+#            goto d
+# f  <2> leaveloop K/2
+# g  <1> leavesub[1 ref] K/REFC,1
 EONT_EONT
 
 pass("GREP: SAMPLES FROM PERLDOC -F GREP");
index 1f81323..25f7335 100644 (file)
@@ -48,104 +48,104 @@ checkOptree ( name        => 'BEGIN',
              strip_open_hints => 1,
              expect    => <<'EOT_EOT', expect_nt => <<'EONT_EONT');
 # BEGIN 1:
-# b  <1> leavesub[1 ref] K/REFC,1 ->(end)
-# -     <@> lineseq KP ->b
+# a  <1> leavesub[1 ref] K/REFC,1 ->(end)
+# -     <@> lineseq KP ->a
 # 1        <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$ ->2
 # 3        <1> require sK/1 ->4
 # 2           <$> const[PV "strict.pm"] s/BARE ->3
 # 4        <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$ ->5
 # -        <@> lineseq K ->-
-# 5           <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$ ->6
-# a           <1> entersub[t1] KS*/TARG,2 ->b
-# 6              <0> pushmark s ->7
-# 7              <$> const[PV "strict"] sM ->8
-# 8              <$> const[PV "refs"] sM ->9
-# 9              <$> method_named[PV "unimport"] ->a
+# -           <0> null ->5
+# 9           <1> entersub[t1] KS*/TARG,2 ->a
+# 5              <0> pushmark s ->6
+# 6              <$> const[PV "strict"] sM ->7
+# 7              <$> const[PV "refs"] sM ->8
+# 8              <$> method_named[PV "unimport"] ->9
 # BEGIN 2:
-# m  <1> leavesub[1 ref] K/REFC,1 ->(end)
-# -     <@> lineseq K ->m
-# c        <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->d
-# e        <1> require sK/1 ->f
-# d           <$> const[PV "strict.pm"] s/BARE ->e
-# f        <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->g
+# k  <1> leavesub[1 ref] K/REFC,1 ->(end)
+# -     <@> lineseq K ->k
+# b        <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->c
+# d        <1> require sK/1 ->e
+# c           <$> const[PV "strict.pm"] s/BARE ->d
+# e        <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->f
 # -        <@> lineseq K ->-
-# g           <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$ ->h
-# l           <1> entersub[t1] KS*/TARG,2 ->m
-# h              <0> pushmark s ->i
-# i              <$> const[PV "strict"] sM ->j
-# j              <$> const[PV "refs"] sM ->k
-# k              <$> method_named[PV "unimport"] ->l
+# -           <0> null ->f
+# j           <1> entersub[t1] KS*/TARG,2 ->k
+# f              <0> pushmark s ->g
+# g              <$> const[PV "strict"] sM ->h
+# h              <$> const[PV "refs"] sM ->i
+# i              <$> method_named[PV "unimport"] ->j
 # BEGIN 3:
-# x  <1> leavesub[1 ref] K/REFC,1 ->(end)
-# -     <@> lineseq KP ->x
-# n        <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->o
-# p        <1> require sK/1 ->q
-# o           <$> const[PV "warnings.pm"] s/BARE ->p
-# q        <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->r
+# u  <1> leavesub[1 ref] K/REFC,1 ->(end)
+# -     <@> lineseq KP ->u
+# l        <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->m
+# n        <1> require sK/1 ->o
+# m           <$> const[PV "warnings.pm"] s/BARE ->n
+# o        <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->p
 # -        <@> lineseq K ->-
-# r           <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$ ->s
-# w           <1> entersub[t1] KS*/TARG,2 ->x
-# s              <0> pushmark s ->t
-# t              <$> const[PV "warnings"] sM ->u
-# u              <$> const[PV "qw"] sM ->v
-# v              <$> method_named[PV "unimport"] ->w
+# -           <0> null ->p
+# t           <1> entersub[t1] KS*/TARG,2 ->u
+# p              <0> pushmark s ->q
+# q              <$> const[PV "warnings"] sM ->r
+# r              <$> const[PV "qw"] sM ->s
+# s              <$> method_named[PV "unimport"] ->t
 # BEGIN 4:
-# 11 <1> leavesub[1 ref] K/REFC,1 ->(end)
-# -     <@> lineseq KP ->11
-# y        <;> nextstate(main 2 -e:1) v:>,<,%,{ ->z
-# 10       <1> postinc[t3] sK/1 ->11
-# -           <1> ex-rv2sv sKRM/1 ->10
-# z              <#> gvsv[*beg] s ->10
+#  <1> leavesub[1 ref] K/REFC,1 ->(end)
+# -     <@> lineseq KP ->y
+# v        <;> nextstate(main 2 -e:1) v:>,<,%,{ ->w
+# x        <1> postinc[t3] sK/1 ->y
+# -           <1> ex-rv2sv sKRM/1 ->x
+# w              <#> gvsv[*beg] s ->x
 EOT_EOT
 # BEGIN 1:
-# b  <1> leavesub[1 ref] K/REFC,1 ->(end)
-# -     <@> lineseq KP ->b
+# a  <1> leavesub[1 ref] K/REFC,1 ->(end)
+# -     <@> lineseq KP ->a
 # 1        <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$ ->2
 # 3        <1> require sK/1 ->4
 # 2           <$> const(PV "strict.pm") s/BARE ->3
 # 4        <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$ ->5
 # -        <@> lineseq K ->-
-# 5           <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$ ->6
-# a           <1> entersub[t1] KS*/TARG,2 ->b
-# 6              <0> pushmark s ->7
-# 7              <$> const(PV "strict") sM ->8
-# 8              <$> const(PV "refs") sM ->9
-# 9              <$> method_named(PV "unimport") ->a
+# -           <0> null ->5
+# 9           <1> entersub[t1] KS*/TARG,2 ->a
+# 5              <0> pushmark s ->6
+# 6              <$> const(PV "strict") sM ->7
+# 7              <$> const(PV "refs") sM ->8
+# 8              <$> method_named(PV "unimport") ->9
 # BEGIN 2:
-# m  <1> leavesub[1 ref] K/REFC,1 ->(end)
-# -     <@> lineseq K ->m
-# c        <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->d
-# e        <1> require sK/1 ->f
-# d           <$> const(PV "strict.pm") s/BARE ->e
-# f        <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->g
+# k  <1> leavesub[1 ref] K/REFC,1 ->(end)
+# -     <@> lineseq K ->k
+# b        <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->c
+# d        <1> require sK/1 ->e
+# c           <$> const(PV "strict.pm") s/BARE ->d
+# e        <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$ ->f
 # -        <@> lineseq K ->-
-# g           <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$ ->h
-# l           <1> entersub[t1] KS*/TARG,2 ->m
-# h              <0> pushmark s ->i
-# i              <$> const(PV "strict") sM ->j
-# j              <$> const(PV "refs") sM ->k
-# k              <$> method_named(PV "unimport") ->l
+# -           <0> null ->f
+# j           <1> entersub[t1] KS*/TARG,2 ->k
+# f              <0> pushmark s ->g
+# g              <$> const(PV "strict") sM ->h
+# h              <$> const(PV "refs") sM ->i
+# i              <$> method_named(PV "unimport") ->j
 # BEGIN 3:
-# x  <1> leavesub[1 ref] K/REFC,1 ->(end)
-# -     <@> lineseq KP ->x
-# n        <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->o
-# p        <1> require sK/1 ->q
-# o           <$> const(PV "warnings.pm") s/BARE ->p
-# q        <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->r
+# u  <1> leavesub[1 ref] K/REFC,1 ->(end)
+# -     <@> lineseq KP ->u
+# l        <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->m
+# n        <1> require sK/1 ->o
+# m           <$> const(PV "warnings.pm") s/BARE ->n
+# o        <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$ ->p
 # -        <@> lineseq K ->-
-# r           <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$ ->s
-# w           <1> entersub[t1] KS*/TARG,2 ->x
-# s              <0> pushmark s ->t
-# t              <$> const(PV "warnings") sM ->u
-# u              <$> const(PV "qw") sM ->v
-# v              <$> method_named(PV "unimport") ->w
+# -           <0> null ->p
+# t           <1> entersub[t1] KS*/TARG,2 ->u
+# p              <0> pushmark s ->q
+# q              <$> const(PV "warnings") sM ->r
+# r              <$> const(PV "qw") sM ->s
+# s              <$> method_named(PV "unimport") ->t
 # BEGIN 4:
-# 11 <1> leavesub[1 ref] K/REFC,1 ->(end)
-# -     <@> lineseq KP ->11
-# y        <;> nextstate(main 2 -e:1) v:>,<,%,{ ->z
-# 10       <1> postinc[t2] sK/1 ->11
-# -           <1> ex-rv2sv sKRM/1 ->10
-# z              <$> gvsv(*beg) s ->10
+#  <1> leavesub[1 ref] K/REFC,1 ->(end)
+# -     <@> lineseq KP ->y
+# v        <;> nextstate(main 2 -e:1) v:>,<,%,{ ->w
+# x        <1> postinc[t2] sK/1 ->y
+# -           <1> ex-rv2sv sKRM/1 ->x
+# w              <$> gvsv(*beg) s ->x
 EONT_EONT
 
 
@@ -253,124 +253,118 @@ checkOptree ( name      => 'all of BEGIN END INIT CHECK UNITCHECK -exec',
 # 2  <$> const[PV "strict.pm"] s/BARE
 # 3  <1> require sK/1
 # 4  <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
-# 5  <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$
-# 6  <0> pushmark s
-# 7  <$> const[PV "strict"] sM
-# 8  <$> const[PV "refs"] sM
-# 9  <$> method_named[PV "unimport"] 
-# a  <1> entersub[t1] KS*/TARG,2
-# b  <1> leavesub[1 ref] K/REFC,1
+# 5  <0> pushmark s
+# 6  <$> const[PV "strict"] sM
+# 7  <$> const[PV "refs"] sM
+# 8  <$> method_named[PV "unimport"] 
+# 9  <1> entersub[t1] KS*/TARG,2
+# a  <1> leavesub[1 ref] K/REFC,1
 # BEGIN 2:
-# c  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# d  <$> const[PV "strict.pm"] s/BARE
-# e  <1> require sK/1
-# f  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# g  <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$
-# h  <0> pushmark s
-# i  <$> const[PV "strict"] sM
-# j  <$> const[PV "refs"] sM
-# k  <$> method_named[PV "unimport"] 
-# l  <1> entersub[t1] KS*/TARG,2
-# m  <1> leavesub[1 ref] K/REFC,1
+# b  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# c  <$> const[PV "strict.pm"] s/BARE
+# d  <1> require sK/1
+# e  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# f  <0> pushmark s
+# g  <$> const[PV "strict"] sM
+# h  <$> const[PV "refs"] sM
+# i  <$> method_named[PV "unimport"] 
+# j  <1> entersub[t1] KS*/TARG,2
+# k  <1> leavesub[1 ref] K/REFC,1
 # BEGIN 3:
-# n  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# o  <$> const[PV "warnings.pm"] s/BARE
-# p  <1> require sK/1
-# q  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# r  <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$
-# s  <0> pushmark s
-# t  <$> const[PV "warnings"] sM
-# u  <$> const[PV "qw"] sM
-# v  <$> method_named[PV "unimport"] 
-# w  <1> entersub[t1] KS*/TARG,2
-# x  <1> leavesub[1 ref] K/REFC,1
+# l  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# m  <$> const[PV "warnings.pm"] s/BARE
+# n  <1> require sK/1
+# o  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# p  <0> pushmark s
+# q  <$> const[PV "warnings"] sM
+# r  <$> const[PV "qw"] sM
+# s  <$> method_named[PV "unimport"] 
+# t  <1> entersub[t1] KS*/TARG,2
+# u  <1> leavesub[1 ref] K/REFC,1
 # BEGIN 4:
-# y  <;> nextstate(main 2 -e:1) v:>,<,%,{
-# z  <#> gvsv[*beg] s
-# 10 <1> postinc[t3] sK/1
-# 11 <1> leavesub[1 ref] K/REFC,1
+# v  <;> nextstate(main 2 -e:1) v:>,<,%,{
+# w  <#> gvsv[*beg] s
+#  <1> postinc[t3] sK/1
+#  <1> leavesub[1 ref] K/REFC,1
 # END 1:
-# 12 <;> nextstate(main 5 -e:1) v:>,<,%,{
-# 13 <#> gvsv[*end] s
-# 14 <1> postinc[t3] sK/1
-# 15 <1> leavesub[1 ref] K/REFC,1
+#  <;> nextstate(main 5 -e:1) v:>,<,%,{
+# 10 <#> gvsv[*end] s
+# 11 <1> postinc[t3] sK/1
+# 12 <1> leavesub[1 ref] K/REFC,1
 # INIT 1:
-# 16 <;> nextstate(main 4 -e:1) v:>,<,%,{
-# 17 <#> gvsv[*init] s
-# 18 <1> postinc[t3] sK/1
-# 19 <1> leavesub[1 ref] K/REFC,1
+# 13 <;> nextstate(main 4 -e:1) v:>,<,%,{
+# 14 <#> gvsv[*init] s
+# 15 <1> postinc[t3] sK/1
+# 16 <1> leavesub[1 ref] K/REFC,1
 # CHECK 1:
-# 1a <;> nextstate(main 3 -e:1) v:>,<,%,{
-# 1b <#> gvsv[*chk] s
-# 1c <1> postinc[t3] sK/1
-# 1d <1> leavesub[1 ref] K/REFC,1
+# 17 <;> nextstate(main 3 -e:1) v:>,<,%,{
+# 18 <#> gvsv[*chk] s
+# 19 <1> postinc[t3] sK/1
+# 1a <1> leavesub[1 ref] K/REFC,1
 # UNITCHECK 1:
-# 1e <;> nextstate(main 6 -e:1) v:>,<,%,{
-# 1f <#> gvsv[*uc] s
-# 1g <1> postinc[t3] sK/1
-# 1h <1> leavesub[1 ref] K/REFC,1
+# 1b <;> nextstate(main 6 -e:1) v:>,<,%,{
+# 1c <#> gvsv[*uc] s
+# 1d <1> postinc[t3] sK/1
+# 1e <1> leavesub[1 ref] K/REFC,1
 EOT_EOT
 # BEGIN 1:
 # 1  <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
 # 2  <$> const(PV "strict.pm") s/BARE
 # 3  <1> require sK/1
 # 4  <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
-# 5  <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$
-# 6  <0> pushmark s
-# 7  <$> const(PV "strict") sM
-# 8  <$> const(PV "refs") sM
-# 9  <$> method_named(PV "unimport") 
-# a  <1> entersub[t1] KS*/TARG,2
-# b  <1> leavesub[1 ref] K/REFC,1
+# 5  <0> pushmark s
+# 6  <$> const(PV "strict") sM
+# 7  <$> const(PV "refs") sM
+# 8  <$> method_named(PV "unimport") 
+# 9  <1> entersub[t1] KS*/TARG,2
+# a  <1> leavesub[1 ref] K/REFC,1
 # BEGIN 2:
-# c  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# d  <$> const(PV "strict.pm") s/BARE
-# e  <1> require sK/1
-# f  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# g  <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$
-# h  <0> pushmark s
-# i  <$> const(PV "strict") sM
-# j  <$> const(PV "refs") sM
-# k  <$> method_named(PV "unimport") 
-# l  <1> entersub[t1] KS*/TARG,2
-# m  <1> leavesub[1 ref] K/REFC,1
+# b  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# c  <$> const(PV "strict.pm") s/BARE
+# d  <1> require sK/1
+# e  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# f  <0> pushmark s
+# g  <$> const(PV "strict") sM
+# h  <$> const(PV "refs") sM
+# i  <$> method_named(PV "unimport") 
+# j  <1> entersub[t1] KS*/TARG,2
+# k  <1> leavesub[1 ref] K/REFC,1
 # BEGIN 3:
-# n  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# o  <$> const(PV "warnings.pm") s/BARE
-# p  <1> require sK/1
-# q  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# r  <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$
-# s  <0> pushmark s
-# t  <$> const(PV "warnings") sM
-# u  <$> const(PV "qw") sM
-# v  <$> method_named(PV "unimport") 
-# w  <1> entersub[t1] KS*/TARG,2
-# x  <1> leavesub[1 ref] K/REFC,1
+# l  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# m  <$> const(PV "warnings.pm") s/BARE
+# n  <1> require sK/1
+# o  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# p  <0> pushmark s
+# q  <$> const(PV "warnings") sM
+# r  <$> const(PV "qw") sM
+# s  <$> method_named(PV "unimport") 
+# t  <1> entersub[t1] KS*/TARG,2
+# u  <1> leavesub[1 ref] K/REFC,1
 # BEGIN 4:
-# y  <;> nextstate(main 2 -e:1) v:>,<,%,{
-# z  <$> gvsv(*beg) s
-# 10 <1> postinc[t2] sK/1
-# 11 <1> leavesub[1 ref] K/REFC,1
+# v  <;> nextstate(main 2 -e:1) v:>,<,%,{
+# w  <$> gvsv(*beg) s
+#  <1> postinc[t2] sK/1
+#  <1> leavesub[1 ref] K/REFC,1
 # END 1:
-# 12 <;> nextstate(main 5 -e:1) v:>,<,%,{
-# 13 <$> gvsv(*end) s
-# 14 <1> postinc[t2] sK/1
-# 15 <1> leavesub[1 ref] K/REFC,1
+#  <;> nextstate(main 5 -e:1) v:>,<,%,{
+# 10 <$> gvsv(*end) s
+# 11 <1> postinc[t2] sK/1
+# 12 <1> leavesub[1 ref] K/REFC,1
 # INIT 1:
-# 16 <;> nextstate(main 4 -e:1) v:>,<,%,{
-# 17 <$> gvsv(*init) s
-# 18 <1> postinc[t2] sK/1
-# 19 <1> leavesub[1 ref] K/REFC,1
+# 13 <;> nextstate(main 4 -e:1) v:>,<,%,{
+# 14 <$> gvsv(*init) s
+# 15 <1> postinc[t2] sK/1
+# 16 <1> leavesub[1 ref] K/REFC,1
 # CHECK 1:
-# 1a <;> nextstate(main 3 -e:1) v:>,<,%,{
-# 1b <$> gvsv(*chk) s
-# 1c <1> postinc[t2] sK/1
-# 1d <1> leavesub[1 ref] K/REFC,1
+# 17 <;> nextstate(main 3 -e:1) v:>,<,%,{
+# 18 <$> gvsv(*chk) s
+# 19 <1> postinc[t2] sK/1
+# 1a <1> leavesub[1 ref] K/REFC,1
 # UNITCHECK 1:
-# 1e <;> nextstate(main 6 -e:1) v:>,<,%,{
-# 1f <$> gvsv(*uc) s
-# 1g <1> postinc[t2] sK/1
-# 1h <1> leavesub[1 ref] K/REFC,1
+# 1b <;> nextstate(main 6 -e:1) v:>,<,%,{
+# 1c <$> gvsv(*uc) s
+# 1d <1> postinc[t2] sK/1
+# 1e <1> leavesub[1 ref] K/REFC,1
 EONT_EONT
 
 
@@ -388,72 +382,66 @@ checkOptree ( name        => 'regression test for patch 25352',
 # 2  <$> const[PV "strict.pm"] s/BARE
 # 3  <1> require sK/1
 # 4  <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
-# 5  <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$
-# 6  <0> pushmark s
-# 7  <$> const[PV "strict"] sM
-# 8  <$> const[PV "refs"] sM
-# 9  <$> method_named[PV "unimport"] 
-# a  <1> entersub[t1] KS*/TARG,2
-# b  <1> leavesub[1 ref] K/REFC,1
+# 5  <0> pushmark s
+# 6  <$> const[PV "strict"] sM
+# 7  <$> const[PV "refs"] sM
+# 8  <$> method_named[PV "unimport"] 
+# 9  <1> entersub[t1] KS*/TARG,2
+# a  <1> leavesub[1 ref] K/REFC,1
 # BEGIN 2:
-# c  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# d  <$> const[PV "strict.pm"] s/BARE
-# e  <1> require sK/1
-# f  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# g  <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$
-# h  <0> pushmark s
-# i  <$> const[PV "strict"] sM
-# j  <$> const[PV "refs"] sM
-# k  <$> method_named[PV "unimport"] 
-# l  <1> entersub[t1] KS*/TARG,2
-# m  <1> leavesub[1 ref] K/REFC,1
+# b  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# c  <$> const[PV "strict.pm"] s/BARE
+# d  <1> require sK/1
+# e  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# f  <0> pushmark s
+# g  <$> const[PV "strict"] sM
+# h  <$> const[PV "refs"] sM
+# i  <$> method_named[PV "unimport"] 
+# j  <1> entersub[t1] KS*/TARG,2
+# k  <1> leavesub[1 ref] K/REFC,1
 # BEGIN 3:
-# n  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# o  <$> const[PV "warnings.pm"] s/BARE
-# p  <1> require sK/1
-# q  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# r  <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$
-# s  <0> pushmark s
-# t  <$> const[PV "warnings"] sM
-# u  <$> const[PV "qw"] sM
-# v  <$> method_named[PV "unimport"] 
-# w  <1> entersub[t1] KS*/TARG,2
-# x  <1> leavesub[1 ref] K/REFC,1
+# l  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# m  <$> const[PV "warnings.pm"] s/BARE
+# n  <1> require sK/1
+# o  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# p  <0> pushmark s
+# q  <$> const[PV "warnings"] sM
+# r  <$> const[PV "qw"] sM
+# s  <$> method_named[PV "unimport"] 
+# t  <1> entersub[t1] KS*/TARG,2
+# u  <1> leavesub[1 ref] K/REFC,1
 EOT_EOT
 # BEGIN 1:
 # 1  <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
 # 2  <$> const(PV "strict.pm") s/BARE
 # 3  <1> require sK/1
 # 4  <;> nextstate(B::Concise -275 Concise.pm:356) v:*,&,{,$
-# 5  <;> nextstate(B::Concise -275 Concise.pm:356) :*,&,{,$
-# 6  <0> pushmark s
-# 7  <$> const(PV "strict") sM
-# 8  <$> const(PV "refs") sM
-# 9  <$> method_named(PV "unimport") 
-# a  <1> entersub[t1] KS*/TARG,2
-# b  <1> leavesub[1 ref] K/REFC,1
+# 5  <0> pushmark s
+# 6  <$> const(PV "strict") sM
+# 7  <$> const(PV "refs") sM
+# 8  <$> method_named(PV "unimport") 
+# 9  <1> entersub[t1] KS*/TARG,2
+# a  <1> leavesub[1 ref] K/REFC,1
 # BEGIN 2:
-# c  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# d  <$> const(PV "strict.pm") s/BARE
-# e  <1> require sK/1
-# f  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
-# g  <;> nextstate(B::Concise -265 Concise.pm:367) :*,&,$
-# h  <0> pushmark s
-# i  <$> const(PV "strict") sM
-# j  <$> const(PV "refs") sM
-# k  <$> method_named(PV "unimport") 
-# l  <1> entersub[t1] KS*/TARG,2
-# m  <1> leavesub[1 ref] K/REFC,1
+# b  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# c  <$> const(PV "strict.pm") s/BARE
+# d  <1> require sK/1
+# e  <;> nextstate(B::Concise -265 Concise.pm:367) v:*,&,$
+# f  <0> pushmark s
+# g  <$> const(PV "strict") sM
+# h  <$> const(PV "refs") sM
+# i  <$> method_named(PV "unimport") 
+# j  <1> entersub[t1] KS*/TARG,2
+# k  <1> leavesub[1 ref] K/REFC,1
 # BEGIN 3:
-# n  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# o  <$> const(PV "warnings.pm") s/BARE
-# p  <1> require sK/1
-# q  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
-# r  <;> nextstate(B::Concise -254 Concise.pm:386) :*,&,{,$
-# s  <0> pushmark s
-# t  <$> const(PV "warnings") sM
-# u  <$> const(PV "qw") sM
-# v  <$> method_named(PV "unimport") 
-# w  <1> entersub[t1] KS*/TARG,2
-# x  <1> leavesub[1 ref] K/REFC,1
+# l  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# m  <$> const(PV "warnings.pm") s/BARE
+# n  <1> require sK/1
+# o  <;> nextstate(B::Concise -254 Concise.pm:386) v:*,&,{,$
+# p  <0> pushmark s
+# q  <$> const(PV "warnings") sM
+# r  <$> const(PV "qw") sM
+# s  <$> method_named(PV "unimport") 
+# t  <1> entersub[t1] KS*/TARG,2
+# u  <1> leavesub[1 ref] K/REFC,1
 EONT_EONT
diff --git a/op.c b/op.c
index 3699674..433face 100644 (file)
--- a/op.c
+++ b/op.c
@@ -8862,10 +8862,62 @@ Perl_rpeep(pTHX_ register OP *o)
        o->op_opt = 1;
        PL_op = o;
        switch (o->op_type) {
-       case OP_NEXTSTATE:
        case OP_DBSTATE:
            PL_curcop = ((COP*)o);              /* for warnings */
            break;
+       case OP_NEXTSTATE:
+           PL_curcop = ((COP*)o);              /* for warnings */
+
+           /* Two NEXTSTATEs in a row serve no purpose. Except if they happen
+              to carry two labels. For now, take the easier option, and skip
+              this optimisation if the first NEXTSTATE has a label.  */
+           if (!CopLABEL((COP*)o)) {
+               OP *nextop = o->op_next;
+               while (nextop && nextop->op_type == OP_NULL)
+                   nextop = nextop->op_next;
+
+               if (nextop && (nextop->op_type == OP_NEXTSTATE)) {
+                   COP *firstcop = (COP *)o;
+                   COP *secondcop = (COP *)nextop;
+                   /* We want the COP pointed to by o (and anything else) to
+                      become the next COP down the line.  */
+                   cop_free(firstcop);
+
+                   firstcop->op_next = secondcop->op_next;
+
+                   /* Now steal all its pointers, and duplicate the other
+                      data.  */
+                   firstcop->cop_line = secondcop->cop_line;
+#ifdef USE_ITHREADS
+                   firstcop->cop_stashpv = secondcop->cop_stashpv;
+                   firstcop->cop_file = secondcop->cop_file;
+#else
+                   firstcop->cop_stash = secondcop->cop_stash;
+                   firstcop->cop_filegv = secondcop->cop_filegv;
+#endif
+                   firstcop->cop_hints = secondcop->cop_hints;
+                   firstcop->cop_seq = secondcop->cop_seq;
+                   firstcop->cop_warnings = secondcop->cop_warnings;
+                   firstcop->cop_hints_hash = secondcop->cop_hints_hash;
+
+#ifdef USE_ITHREADS
+                   secondcop->cop_stashpv = NULL;
+                   secondcop->cop_file = NULL;
+#else
+                   secondcop->cop_stash = NULL;
+                   secondcop->cop_filegv = NULL;
+#endif
+                   secondcop->cop_warnings = NULL;
+                   secondcop->cop_hints_hash = NULL;
+
+                   /* If we use op_null(), and hence leave an ex-COP, some
+                      warnings are misreported. For example, the compile-time
+                      error in 'use strict; no strict refs;'  */
+                   secondcop->op_type = OP_NULL;
+                   secondcop->op_ppaddr = PL_ppaddr[OP_NULL];
+               }
+           }
+           break;
 
        case OP_CONST:
            if (cSVOPo->op_private & OPpCONST_STRICT)
index 0a8aeee..a98e354 100644 (file)
@@ -10,7 +10,7 @@ BEGIN {
 
 use warnings;
 use strict;
-plan tests => 67;
+plan tests => 68;
 our $TODO;
 
 my $deprecated = 0;
@@ -483,3 +483,9 @@ is($deprecated, 0);
     is($x, 10,
        'labels outside evals can be distinguished from the start of the eval');
 }
+
+goto wham_eth;
+die "You can't get here";
+
+wham_eth: 1 if 0;
+ouch_eth: pass('labels persist even if their statement is optimised away');