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);