Mercurial > vim
comparison src/vim9compile.c @ 23723:14e92f4c98c9 v8.2.2403
patch 8.2.2403: Vim9: profiling if/elseif/endif not correct
Commit: https://github.com/vim/vim/commit/ced68a0070dac059fc978a1a99e2893edf158116
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Jan 24 17:53:47 2021 +0100
patch 8.2.2403: Vim9: profiling if/elseif/endif not correct
Problem: Vim9: profiling if/elseif/endif not correct.
Solution: Add profile instructions. Fix that "elseif" was wrong.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 24 Jan 2021 18:00:04 +0100 |
parents | 1a7c2685d780 |
children | f98692ae09a0 |
comparison
equal
deleted
inserted
replaced
23722:a889925d20fd | 23723:14e92f4c98c9 |
---|---|
42 /* | 42 /* |
43 * info specific for the scope of :if / elseif / else | 43 * info specific for the scope of :if / elseif / else |
44 */ | 44 */ |
45 typedef struct { | 45 typedef struct { |
46 int is_seen_else; | 46 int is_seen_else; |
47 int is_seen_skip_not; // a block was unconditionally executed | |
47 int is_had_return; // every block ends in :return | 48 int is_had_return; // every block ends in :return |
48 int is_if_label; // instruction idx at IF or ELSEIF | 49 int is_if_label; // instruction idx at IF or ELSEIF |
49 endlabel_T *is_end_label; // instructions to set end label | 50 endlabel_T *is_end_label; // instructions to set end label |
50 } ifscope_T; | 51 } ifscope_T; |
51 | 52 |
2096 #ifdef FEAT_PROFILE | 2097 #ifdef FEAT_PROFILE |
2097 static void | 2098 static void |
2098 may_generate_prof_end(cctx_T *cctx, int prof_lnum) | 2099 may_generate_prof_end(cctx_T *cctx, int prof_lnum) |
2099 { | 2100 { |
2100 if (cctx->ctx_profiling && prof_lnum >= 0) | 2101 if (cctx->ctx_profiling && prof_lnum >= 0) |
2101 { | |
2102 int save_lnum = cctx->ctx_lnum; | |
2103 | |
2104 cctx->ctx_lnum = prof_lnum; | |
2105 generate_instr(cctx, ISN_PROF_END); | 2102 generate_instr(cctx, ISN_PROF_END); |
2106 cctx->ctx_lnum = save_lnum; | |
2107 } | |
2108 } | 2103 } |
2109 #endif | 2104 #endif |
2110 | 2105 |
2111 /* | 2106 /* |
2112 * Reserve space for a local variable. | 2107 * Reserve space for a local variable. |
6733 generate_JUMP(cctx, JUMP_IF_FALSE, 0); | 6728 generate_JUMP(cctx, JUMP_IF_FALSE, 0); |
6734 } | 6729 } |
6735 else | 6730 else |
6736 scope->se_u.se_if.is_if_label = -1; | 6731 scope->se_u.se_if.is_if_label = -1; |
6737 | 6732 |
6733 #ifdef FEAT_PROFILE | |
6734 if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES | |
6735 && skip_save != SKIP_YES) | |
6736 { | |
6737 // generated a profile start, need to generate a profile end, since it | |
6738 // won't be done after returning | |
6739 cctx->ctx_skip = SKIP_NOT; | |
6740 generate_instr(cctx, ISN_PROF_END); | |
6741 cctx->ctx_skip = SKIP_YES; | |
6742 } | |
6743 #endif | |
6744 | |
6738 return p; | 6745 return p; |
6739 } | 6746 } |
6740 | 6747 |
6741 static char_u * | 6748 static char_u * |
6742 compile_elseif(char_u *arg, cctx_T *cctx) | 6749 compile_elseif(char_u *arg, cctx_T *cctx) |
6756 } | 6763 } |
6757 unwind_locals(cctx, scope->se_local_count); | 6764 unwind_locals(cctx, scope->se_local_count); |
6758 if (!cctx->ctx_had_return) | 6765 if (!cctx->ctx_had_return) |
6759 scope->se_u.se_if.is_had_return = FALSE; | 6766 scope->se_u.se_if.is_had_return = FALSE; |
6760 | 6767 |
6768 if (cctx->ctx_skip == SKIP_NOT) | |
6769 { | |
6770 // previous block was executed, this one and following will not | |
6771 cctx->ctx_skip = SKIP_YES; | |
6772 scope->se_u.se_if.is_seen_skip_not = TRUE; | |
6773 } | |
6774 if (scope->se_u.se_if.is_seen_skip_not) | |
6775 { | |
6776 // A previous block was executed, skip over expression and bail out. | |
6777 // Do not count the "elseif" for profiling. | |
6778 #ifdef FEAT_PROFILE | |
6779 if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] | |
6780 .isn_type == ISN_PROF_START) | |
6781 --instr->ga_len; | |
6782 #endif | |
6783 skip_expr_cctx(&p, cctx); | |
6784 return p; | |
6785 } | |
6786 | |
6761 if (cctx->ctx_skip == SKIP_UNKNOWN) | 6787 if (cctx->ctx_skip == SKIP_UNKNOWN) |
6762 { | 6788 { |
6763 if (compile_jump_to_end(&scope->se_u.se_if.is_end_label, | 6789 if (compile_jump_to_end(&scope->se_u.se_if.is_end_label, |
6764 JUMP_ALWAYS, cctx) == FAIL) | 6790 JUMP_ALWAYS, cctx) == FAIL) |
6765 return NULL; | 6791 return NULL; |
6769 } | 6795 } |
6770 | 6796 |
6771 // compile "expr"; if we know it evaluates to FALSE skip the block | 6797 // compile "expr"; if we know it evaluates to FALSE skip the block |
6772 CLEAR_FIELD(ppconst); | 6798 CLEAR_FIELD(ppconst); |
6773 if (cctx->ctx_skip == SKIP_YES) | 6799 if (cctx->ctx_skip == SKIP_YES) |
6800 { | |
6774 cctx->ctx_skip = SKIP_UNKNOWN; | 6801 cctx->ctx_skip = SKIP_UNKNOWN; |
6802 #ifdef FEAT_PROFILE | |
6803 if (cctx->ctx_profiling) | |
6804 { | |
6805 // the previous block was skipped, need to profile this line | |
6806 generate_instr(cctx, ISN_PROF_START); | |
6807 instr_count = instr->ga_len; | |
6808 } | |
6809 #endif | |
6810 } | |
6775 if (compile_expr1(&p, cctx, &ppconst) == FAIL) | 6811 if (compile_expr1(&p, cctx, &ppconst) == FAIL) |
6776 { | 6812 { |
6777 clear_ppconst(&ppconst); | 6813 clear_ppconst(&ppconst); |
6778 return NULL; | 6814 return NULL; |
6779 } | 6815 } |
6827 unwind_locals(cctx, scope->se_local_count); | 6863 unwind_locals(cctx, scope->se_local_count); |
6828 if (!cctx->ctx_had_return) | 6864 if (!cctx->ctx_had_return) |
6829 scope->se_u.se_if.is_had_return = FALSE; | 6865 scope->se_u.se_if.is_had_return = FALSE; |
6830 scope->se_u.se_if.is_seen_else = TRUE; | 6866 scope->se_u.se_if.is_seen_else = TRUE; |
6831 | 6867 |
6832 if (scope->se_skip_save != SKIP_YES) | 6868 #ifdef FEAT_PROFILE |
6869 if (cctx->ctx_profiling) | |
6870 { | |
6871 if (cctx->ctx_skip == SKIP_NOT | |
6872 && ((isn_T *)instr->ga_data)[instr->ga_len - 1] | |
6873 .isn_type == ISN_PROF_START) | |
6874 // the previous block was executed, do not count "else" for profiling | |
6875 --instr->ga_len; | |
6876 if (cctx->ctx_skip == SKIP_YES && !scope->se_u.se_if.is_seen_skip_not) | |
6877 { | |
6878 // the previous block was not executed, this one will, do count the | |
6879 // "else" for profiling | |
6880 cctx->ctx_skip = SKIP_NOT; | |
6881 generate_instr(cctx, ISN_PROF_END); | |
6882 generate_instr(cctx, ISN_PROF_START); | |
6883 cctx->ctx_skip = SKIP_YES; | |
6884 } | |
6885 } | |
6886 #endif | |
6887 | |
6888 if (!scope->se_u.se_if.is_seen_skip_not && scope->se_skip_save != SKIP_YES) | |
6833 { | 6889 { |
6834 // jump from previous block to the end, unless the else block is empty | 6890 // jump from previous block to the end, unless the else block is empty |
6835 if (cctx->ctx_skip == SKIP_UNKNOWN) | 6891 if (cctx->ctx_skip == SKIP_UNKNOWN) |
6836 { | 6892 { |
6837 if (!cctx->ctx_had_return | 6893 if (!cctx->ctx_had_return |
6882 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label; | 6938 isn = ((isn_T *)instr->ga_data) + scope->se_u.se_if.is_if_label; |
6883 isn->isn_arg.jump.jump_where = instr->ga_len; | 6939 isn->isn_arg.jump.jump_where = instr->ga_len; |
6884 } | 6940 } |
6885 // Fill in the "end" label in jumps at the end of the blocks. | 6941 // Fill in the "end" label in jumps at the end of the blocks. |
6886 compile_fill_jump_to_end(&ifscope->is_end_label, cctx); | 6942 compile_fill_jump_to_end(&ifscope->is_end_label, cctx); |
6943 | |
6944 #ifdef FEAT_PROFILE | |
6945 // even when skipping we count the endif as executed, unless the block it's | |
6946 // in is skipped | |
6947 if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES | |
6948 && scope->se_skip_save != SKIP_YES) | |
6949 { | |
6950 cctx->ctx_skip = SKIP_NOT; | |
6951 generate_instr(cctx, ISN_PROF_START); | |
6952 } | |
6953 #endif | |
6887 cctx->ctx_skip = scope->se_skip_save; | 6954 cctx->ctx_skip = scope->se_skip_save; |
6888 | 6955 |
6889 // If all the blocks end in :return and there is an :else then the | 6956 // If all the blocks end in :return and there is an :else then the |
6890 // had_return flag is set. | 6957 // had_return flag is set. |
6891 cctx->ctx_had_return = ifscope->is_had_return && ifscope->is_seen_else; | 6958 cctx->ctx_had_return = ifscope->is_had_return && ifscope->is_seen_else; |
8003 line = next_line_from_context(&cctx, FALSE); | 8070 line = next_line_from_context(&cctx, FALSE); |
8004 if (cctx.ctx_lnum >= ufunc->uf_lines.ga_len) | 8071 if (cctx.ctx_lnum >= ufunc->uf_lines.ga_len) |
8005 { | 8072 { |
8006 // beyond the last line | 8073 // beyond the last line |
8007 #ifdef FEAT_PROFILE | 8074 #ifdef FEAT_PROFILE |
8008 may_generate_prof_end(&cctx, prof_lnum); | 8075 if (cctx.ctx_skip != SKIP_YES) |
8076 may_generate_prof_end(&cctx, prof_lnum); | |
8009 #endif | 8077 #endif |
8010 break; | 8078 break; |
8011 } | 8079 } |
8012 } | 8080 } |
8013 | 8081 |
8021 line = (char_u *)""; | 8089 line = (char_u *)""; |
8022 continue; | 8090 continue; |
8023 } | 8091 } |
8024 | 8092 |
8025 #ifdef FEAT_PROFILE | 8093 #ifdef FEAT_PROFILE |
8026 if (cctx.ctx_profiling && cctx.ctx_lnum != prof_lnum) | 8094 if (cctx.ctx_profiling && cctx.ctx_lnum != prof_lnum && |
8095 cctx.ctx_skip != SKIP_YES) | |
8027 { | 8096 { |
8028 may_generate_prof_end(&cctx, prof_lnum); | 8097 may_generate_prof_end(&cctx, prof_lnum); |
8029 | 8098 |
8030 prof_lnum = cctx.ctx_lnum; | 8099 prof_lnum = cctx.ctx_lnum; |
8031 generate_instr(&cctx, ISN_PROF_START); | 8100 generate_instr(&cctx, ISN_PROF_START); |