From affa7430b70336b53cd496496d889c2544d41322 Mon Sep 17 00:00:00 2001 From: ko1 Date: Mon, 21 May 2007 04:46:51 +0000 Subject: * compile.c, vm_macro.def: support tail call optimization (on default, this feature is not enabled). * iseq.c, compile.c, vm_opts.h: add "tailcall_optimization" option. * sample/test.rb (test_ok): fix to adjust tailcall stack layout. * insns.def, vm.c, compile.c, yarvcore.c, yarvcore.h: add opt_gt, opt_le instructions. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12304 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 13 +++++++++++ compile.c | 54 +++++++++++++++++++++++++++++++++++--------- insns.def | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ iseq.c | 11 ++++++--- sample/test.rb | 2 +- version.h | 6 ++--- vm.c | 2 ++ vm.h | 2 ++ vm_macro.def | 41 +++++++++++++++++++--------------- vm_opts.h | 3 ++- yarvcore.c | 4 ++++ yarvcore.h | 3 +++ 12 files changed, 174 insertions(+), 37 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0a8d9fe02b..5a3afa1652 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Mon May 21 13:40:00 2007 Koichi Sasada + + * compile.c, vm_macro.def: support tail call optimization + (on default, this feature is not enabled). + + * iseq.c, compile.c, vm_opts.h: add "tailcall_optimization" + option. + + * sample/test.rb (test_ok): fix to adjust tailcall stack layout. + + * insns.def, vm.c, compile.c, yarvcore.c, yarvcore.h: + add opt_gt, opt_le instructions. + Mon May 21 03:34:06 2007 Minero Aoki * lib/net/smtp.rb: CRAM-MD5 authentication did not work. diff --git a/compile.c b/compile.c index 568c792b44..c539e93050 100644 --- a/compile.c +++ b/compile.c @@ -1347,7 +1347,7 @@ get_prev_insn(INSN *iobj) } static int -iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list) +iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt) { INSN *iobj = (INSN *)list; again: @@ -1367,6 +1367,12 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list) niobj = (INSN *)get_next_insn(iobj); if (diobj == niobj) { + /* + * jump LABEL + * LABEL: + * => + * LABEL: + */ REMOVE_ELEM(&iobj->link); } else if (iobj != diobj && diobj->insn_id == BIN(jump)) { @@ -1374,11 +1380,23 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list) goto again; } else if (diobj->insn_id == BIN(leave)) { + /* + * jump LABEL + * ... + * LABEL: + * leave + * => + * leave + * ... + * LABEL: + * leave + */ INSN *eiobj = new_insn_core(iseq, iobj->line_no, BIN(leave), diobj->operand_size, diobj->operands); /* replace */ REPLACE_ELEM((LINK_ELEMENT *)iobj, (LINK_ELEMENT *)eiobj); + iobj = eiobj; } /* * useless jump elimination (if/unless destination): @@ -1405,6 +1423,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list) } } } + if (iobj->insn_id == BIN(branchif) || iobj->insn_id == BIN(branchunless)) { /* @@ -1421,14 +1440,20 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list) } } - if (iobj->insn_id == BIN(leave)) { + if (do_tailcallopt && iobj->insn_id == BIN(leave)) { + /* + * send ... + * leave + * => + * send ..., ... | VM_CALL_TAILCALL_BIT, ... + * leave # unreachable + */ INSN *piobj = (INSN *)get_prev_insn((INSN *)list); - if (piobj->insn_id == BIN(send)) { - /* TODO: tail call optimization */ - if (piobj->operands[2] == 0) { - /* piobj->operands[3] = INT2FIX(FIX2INT(piobj->operands[3]) | VM_CALL_TAILCALL_BIT); */ - /* piobj->operands[3] = INT2FIX(FIX2INT(piobj->operands[3]) | VM_CALL_TAILRECURSION_BIT); */ - } + + if (piobj->insn_id == BIN(send) && + piobj->operands[2] == 0 /* block */ + ) { + piobj->operands[3] = INT2FIX(FIX2INT(piobj->operands[3]) | VM_CALL_TAILCALL_BIT); } } return COMPILE_OK; @@ -1489,6 +1514,12 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj) else if (mid == idLE) { insn_set_specialized_instruction(iobj, BIN(opt_le)); } + else if (mid == idGT) { + insn_set_specialized_instruction(iobj, BIN(opt_gt)); + } + else if (mid == idGE) { + insn_set_specialized_instruction(iobj, BIN(opt_ge)); + } else if (mid == idLTLT) { insn_set_specialized_instruction(iobj, BIN(opt_ltlt)); } @@ -1510,15 +1541,16 @@ static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor) { LINK_ELEMENT *list; - const int do_peephole = iseq->compile_data->option->peephole_optimization; + const int do_peepholeopt = iseq->compile_data->option->peephole_optimization; + const int do_tailcallopt = iseq->compile_data->option->tailcall_optimization; const int do_si = iseq->compile_data->option->specialized_instruction; const int do_ou = iseq->compile_data->option->operands_unification; list = FIRST_ELEMENT(anchor); while (list) { if (list->type == ISEQ_ELEMENT_INSN) { - if (do_peephole) { - iseq_peephole_optimize(iseq, list); + if (do_peepholeopt) { + iseq_peephole_optimize(iseq, list, do_tailcallopt); } if (do_si) { iseq_specialized_instruction(iseq, (INSN *)list); diff --git a/insns.def b/insns.def index 3631ac4ebd..8272f4aac1 100644 --- a/insns.def +++ b/insns.def @@ -2137,6 +2137,76 @@ opt_le } } +/** + @c optimize + @e optimized X>Y. + @j 最適化された X>Y。 + */ +DEFINE_INSN +opt_gt +() +(VALUE recv, VALUE obj) +(VALUE val) +{ + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_GT)) { + long a = FIX2LONG(recv), b = FIX2LONG(obj); + + if (a > b) { + val = Qtrue; + } + else { + val = Qfalse; + } + } + else { + /* other */ +#ifdef YARV_AOT_COMPILED + val = rb_funcall(recv, idGT, 1, obj); +#else + PUSH(recv); + PUSH(obj); + tmp_id = idGT; + goto LABEL_IS_SC(start_init_in_send_for_opt_1); +#endif + } +} + +/** + @c optimize + @e optimized X>=Y. + @j 最適化された X>=Y。 + */ +DEFINE_INSN +opt_ge +() +(VALUE recv, VALUE obj) +(VALUE val) +{ + if (FIXNUM_2_P(recv, obj) && + BASIC_OP_UNREDEFINED_P(BOP_GE)) { + long a = FIX2LONG(recv), b = FIX2LONG(obj); + + if (a >= b) { + val = Qtrue; + } + else { + val = Qfalse; + } + } + else { + /* other */ +#ifdef YARV_AOT_COMPILED + val = rb_funcall(recv, idGE, 1, obj); +#else + PUSH(recv); + PUSH(obj); + tmp_id = idGE; + goto LABEL_IS_SC(start_init_in_send_for_opt_1); +#endif + } +} + /** @c optimize @e << diff --git a/iseq.c b/iseq.c index 11d5b9cbaa..e8c75d5625 100644 --- a/iseq.c +++ b/iseq.c @@ -196,11 +196,12 @@ cleanup_iseq_build(rb_iseq_t *iseq) static rb_compile_option_t COMPILE_OPTION_DEFAULT = { OPT_INLINE_CONST_CACHE, /* int inline_const_cache; */ OPT_PEEPHOLE_OPTIMIZATION, /* int peephole_optimization; */ + OPT_TAILCALL_OPTIMIZATION, /* int tailcall_optimization */ OPT_SPECIALISED_INSTRUCTION, /* int specialized_instruction; */ OPT_OPERANDS_UNIFICATION, /* int operands_unification; */ OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */ OPT_STACK_CACHING, /* int stack_caching; */ - OPT_TRACE_INSTRUCTION, + OPT_TRACE_INSTRUCTION, /* int trace_instruction */ }; static const rb_compile_option_t COMPILE_OPTION_FALSE; @@ -217,13 +218,16 @@ make_compile_option(rb_compile_option_t *option, VALUE opt) memset(option, 1, sizeof(rb_compile_option_t)); } else if (CLASS_OF(opt) == rb_cHash) { + *option = COMPILE_OPTION_DEFAULT; + #define SET_COMPILE_OPTION(o, h, mem) \ - { VALUE flag = rb_hash_aref(h, ID2SYM(rb_intern(#mem))); dp(flag);\ + { VALUE flag = rb_hash_aref(h, ID2SYM(rb_intern(#mem))); \ if (flag == Qtrue) { o->mem = 1; } \ - if (flag == Qfalse) { o->mem = 0; } \ + else if (flag == Qfalse) { o->mem = 0; } \ } SET_COMPILE_OPTION(option, opt, inline_const_cache); SET_COMPILE_OPTION(option, opt, peephole_optimization); + SET_COMPILE_OPTION(option, opt, tailcall_optimization); SET_COMPILE_OPTION(option, opt, specialized_instruction); SET_COMPILE_OPTION(option, opt, operands_unification); SET_COMPILE_OPTION(option, opt, instructions_unification); @@ -245,6 +249,7 @@ make_compile_option_value(rb_compile_option_t *option) { SET_COMPILE_OPTION(option, opt, inline_const_cache); SET_COMPILE_OPTION(option, opt, peephole_optimization); + SET_COMPILE_OPTION(option, opt, tailcall_optimization); SET_COMPILE_OPTION(option, opt, specialized_instruction); SET_COMPILE_OPTION(option, opt, operands_unification); SET_COMPILE_OPTION(option, opt, instructions_unification); diff --git a/sample/test.rb b/sample/test.rb index 7200ad41bf..da44b180f3 100644 --- a/sample/test.rb +++ b/sample/test.rb @@ -17,7 +17,7 @@ def test_ok(cond,n=1) if cond printf "ok %d\n", $testnum else - where = caller(n)[0] + where = (st = caller(n)) ? st[0] : "caller error! (n=#{n}, trace=#{caller(0).join(', ')}" printf "not ok %s %d -- %s\n", $what, $testnum, where $failed+=1 end diff --git a/version.h b/version.h index 11754656c6..ca5979f19f 100644 --- a/version.h +++ b/version.h @@ -1,7 +1,7 @@ #define RUBY_VERSION "1.9.0" -#define RUBY_RELEASE_DATE "2007-05-19" +#define RUBY_RELEASE_DATE "2007-05-21" #define RUBY_VERSION_CODE 190 -#define RUBY_RELEASE_CODE 20070519 +#define RUBY_RELEASE_CODE 20070521 #define RUBY_PATCHLEVEL 0 #define RUBY_VERSION_MAJOR 1 @@ -9,7 +9,7 @@ #define RUBY_VERSION_TEENY 0 #define RUBY_RELEASE_YEAR 2007 #define RUBY_RELEASE_MONTH 5 -#define RUBY_RELEASE_DAY 19 +#define RUBY_RELEASE_DAY 21 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; diff --git a/vm.c b/vm.c index d1a0b34e37..3337117f2c 100644 --- a/vm.c +++ b/vm.c @@ -1480,6 +1480,8 @@ yarv_init_redefined_flag(void) idASET, BOP_ASET, rb_cArray, rb_cHash, 0, idLength, BOP_LENGTH, rb_cArray, rb_cString, rb_cHash, 0, idSucc, BOP_SUCC, rb_cFixnum, rb_cString, rb_cTime, 0, + idGT, BOP_GT, rb_cFixnum, 0, + idGE, BOP_GE, rb_cFixnum, 0, 0, }; VALUE *ptr = register_info; diff --git a/vm.h b/vm.h index 930947086d..457922ceba 100644 --- a/vm.h +++ b/vm.h @@ -283,5 +283,7 @@ default: \ #define BOP_ASET 0x400 #define BOP_LENGTH 0x800 #define BOP_SUCC 0x1000 +#define BOP_GT 0x2000 +#define BOP_GE 0x4000 #endif /* _VM_H_INCLUDED_ */ diff --git a/vm_macro.def b/vm_macro.def index dff6b98c9c..adeaa52ac6 100644 --- a/vm_macro.def +++ b/vm_macro.def @@ -198,33 +198,38 @@ MACRO macro_eval_invoke_func(niseqval, recv, klass, blockptr, num) rb_exc_raise(sysstack_error); } - for (i = 0; i < clear_local_size; i++) { - *sp++ = Qnil; - } + if (flag & VM_CALL_TAILCALL_BIT) { + /* copy arguments */ + VALUE *p_rsp, *p_sp; + reg_cfp = ++th->cfp; + p_rsp = th->cfp->sp; + + for (i=0; i < (sp - rsp); i++) { + p_rsp[i] = rsp[i]; + } + + sp -= rsp - p_rsp; - if (0 && (flag & VM_CALL_TAILCALL_BIT)) { - th->cfp++; - push_frame(th, niseq, FRAME_MAGIC_METHOD, - recv, (VALUE) blockptr, + for (i = 0; i < clear_local_size; i++) { + *sp++ = Qnil; + } + + push_frame(th, niseq, + FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, niseq->iseq_encoded + opt_pc, sp, 0, 0); } - else if (0 && - (flag & VM_CALL_TAILRECURSION_BIT) && niseq == GET_ISEQ()) { - /* do nothing */ - GET_CFP()->self = recv; - SET_LFP(sp); - SET_DFP(sp); - *sp++ = (VALUE) blockptr; - reg_cfp->sp = sp; - reg_cfp->bp = sp; - SET_PC(niseq->iseq_encoded + opt_pc); - } else { + for (i = 0; i < clear_local_size; i++) { + *sp++ = Qnil; + } + push_frame(th, niseq, FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, niseq->iseq_encoded + opt_pc, sp, 0, 0); + reg_cfp->sp = rsp; } + RESTORE_REGS(); } diff --git a/vm_opts.h b/vm_opts.h index 041cef7faa..32b00ac79a 100644 --- a/vm_opts.h +++ b/vm_opts.h @@ -22,10 +22,11 @@ /* VM running option */ #define OPT_CHECKED_RUN 1 -#define OPT_TRACE_INSTRUCTION 1 +#define OPT_TRACE_INSTRUCTION 0 /* default value */ /* at compile */ #define OPT_INLINE_CONST_CACHE 1 +#define OPT_TAILCALL_OPTIMIZATION 0 /* default value */ #define OPT_PEEPHOLE_OPTIMIZATION 1 #define OPT_SPECIALISED_INSTRUCTION 1 diff --git a/yarvcore.c b/yarvcore.c index cb66e67892..0d2dcecd81 100644 --- a/yarvcore.c +++ b/yarvcore.c @@ -31,6 +31,8 @@ ID idMOD; ID idLT; ID idLTLT; ID idLE; +ID idGT; +ID idGE; ID idEq; ID idEqq; ID idBackquote; @@ -495,6 +497,8 @@ Init_VM(void) idLT = rb_intern("<"); idLTLT = rb_intern("<<"); idLE = rb_intern("<="); + idGT = rb_intern(">"); + idGE = rb_intern(">="); idEq = rb_intern("=="); idEqq = rb_intern("==="); idBackquote = rb_intern("`"); diff --git a/yarvcore.h b/yarvcore.h index 0ff3e9b011..61bd53764b 100644 --- a/yarvcore.h +++ b/yarvcore.h @@ -109,6 +109,8 @@ extern ID idMOD; extern ID idLT; extern ID idLTLT; extern ID idLE; +extern ID idGT; +extern ID idGE; extern ID idEq; extern ID idEqq; extern ID idBackquote; @@ -182,6 +184,7 @@ struct iseq_compile_data_ensure_node_stack; typedef struct rb_compile_option_struct { int inline_const_cache; int peephole_optimization; + int tailcall_optimization; int specialized_instruction; int operands_unification; int instructions_unification; -- cgit v1.2.1