@@ -556,9 +556,7 @@ void emitStoreGenYieldPoint(
556556 asmjit::Label resume_label,
557557 arch::Gp suspend_data_r,
558558 arch::Gp scratch_r) {
559- bool is_yield_from = yield->isYieldFrom () ||
560- yield->isYieldFromSkipInitialSend () ||
561- yield->isYieldFromHandleStopAsyncIteration ();
559+ bool is_yield_from = yield->isInYieldFromContext ();
562560
563561 auto calc_spill_offset = [&](size_t live_input_n) {
564562 PhyLocation mem = yield->getInput (live_input_n)->getStackSlot ();
@@ -577,8 +575,9 @@ void emitStoreGenYieldPoint(
577575 live_regs_input - num_live_regs,
578576 live_regs_input);
579577
580- auto yield_from_offset =
581- is_yield_from ? calc_spill_offset (2 ) : kInvalidYieldFromOffset ;
578+ auto yield_from_offset = is_yield_from
579+ ? calc_spill_offset (yield->yieldFromInputIdx ())
580+ : kInvalidYieldFromOffset ;
582581 GenYieldPoint* gen_yield_point = env->code_rt ->addGenYieldPoint (
583582 GenYieldPoint{deopt_idx, yield_from_offset});
584583
@@ -836,6 +835,16 @@ void translateYieldValue(Environ* env, const Instruction* instr) {
836835 // Resumed execution in this generator begins here
837836 as->bind (resume_label);
838837
838+ #if PY_VERSION_HEX < 0x030C0000
839+ // On 3.10, for yield-from yield points, store the finish_yield_from arg
840+ // (RDX from resume entry) into GenDataFooter so the subsequent Send
841+ // instruction can load it.
842+ if (instr->isInYieldFromContext ()) {
843+ auto fyf_offset = offsetof (GenDataFooter, finishYieldFrom);
844+ as->mov (x86::qword_ptr (x86::rbp, fyf_offset), x86::rdx);
845+ }
846+ #endif
847+
839848 // Sent in value is in RSI, and tstate is in RCX from resume entry-point args
840849 emitLoadResumedYieldInputs (as, instr, RSI , x86::rcx);
841850#elif defined(CINDER_AARCH64)
@@ -862,168 +871,20 @@ void translateYieldValue(Environ* env, const Instruction* instr) {
862871 // Resumed execution in this generator begins here
863872 as->bind (resume_label);
864873
865- // Sent in value is in x1, and tstate is in x3 from resume entry-point args
866- emitLoadResumedYieldInputs (as, instr, X1 , a64::x3);
867- #else
868- CINDER_UNSUPPORTED
869- #endif
870- }
871-
872- void translateYieldFrom (Environ* env, const Instruction* instr) {
873- #if defined(CINDER_X86_64)
874- arch::Builder* as = env->as ;
875- bool skip_initial_send = instr->isYieldFromSkipInitialSend ();
876-
877- // Make sure tstate is in RDI for use in epilogue and here.
878- PhyLocation tstate = instr->getInput (0 )->getStackSlot ();
879- auto tstate_phys_reg = x86::rdi;
880- as->mov (tstate_phys_reg, x86::ptr (x86::rbp, tstate.loc ));
881-
882- // If we're skipping the initial send the send value is actually the first
883- // value to yield and so needs to go into RAX to be returned. Otherwise,
884- // put initial send value in RSI, the same location future send values will
885- // be on resume.
886- PhyLocation send_value = instr->getInput (1 )->getStackSlot ();
887- const auto send_value_phys_reg = skip_initial_send ? RAX : RSI ;
888- as->mov (
889- x86::gpq (send_value_phys_reg.loc ), x86::ptr (x86::rbp, send_value.loc ));
890-
891- asmjit::Label yield_label = as->newLabel ();
892- if (skip_initial_send) {
893- as->jmp (yield_label);
894- } else {
895- // Setup call to JITRT_GenSend
896-
897- // Put tstate and the current generator into RCX and RDI respectively, and
898- // set finish_yield_from (RDX) to 0. This register setup matches that when
899- // `resume_label` is reached from the resume entry.
900- auto gen_offs = offsetof (GenDataFooter, gen);
901- as->mov (x86::rcx, tstate_phys_reg);
902- as->mov (x86::rdi, x86::ptr (x86::rbp, gen_offs));
903- as->xor_ (x86::rdx, x86::rdx);
904- }
905-
906- // Resumed execution begins here
907- auto resume_label = as->newLabel ();
908- as->bind (resume_label);
909-
910- // Save tstate from resume to callee-saved reigster.
911- as->mov (x86::rbx, x86::rcx);
912-
913- // 'send_value', and 'finish_yield_from' will already be in RSI and RCX
914- // respectively, either from code above on initial start or from resume entry
915- // point args.
916-
917- // Load sub-iterator into RDI
918- PhyLocation iter_slot = instr->getInput (2 )->getStackSlot ();
919- as->mov (x86::rdi, x86::ptr (x86::rbp, iter_slot.loc ));
920-
921- uint64_t func = reinterpret_cast <uint64_t >(
922- instr->isYieldFromHandleStopAsyncIteration ()
923- ? JITRT_GenSendHandleStopAsyncIteration
924- : JITRT_GenSend);
925- emitCall (*env, func, instr);
926- // Yielded or final result value now in RAX. If the result was nullptr then
927- // done will be set so we'll correctly jump to the following CheckExc.
928- const auto yf_result_phys_reg = RAX ;
929- const auto done_r = x86::rdx;
930-
931- // Restore tstate from callee-saved register.
932- as->mov (tstate_phys_reg, x86::rbx);
933-
934- // If not done, jump to epilogue which will yield/return the value from
935- // JITRT_GenSend in RAX.
936- as->test (done_r, done_r);
937- asmjit::Label done_label = as->newLabel ();
938- as->jnz (done_label);
939-
940- as->bind (yield_label);
941- // Arbitrary scratch register for use in emitStoreGenYieldPoint()
942- auto scratch_r = x86::r9;
943- emitStoreGenYieldPoint (as, env, instr, resume_label, x86::rbp, scratch_r);
944- as->jmp (env->exit_for_yield_label );
945-
946- as->bind (done_label);
947- emitLoadResumedYieldInputs (as, instr, yf_result_phys_reg, tstate_phys_reg);
948- #elif defined(CINDER_AARCH64)
949- arch::Builder* as = env->as ;
950- bool skip_initial_send = instr->isYieldFromSkipInitialSend ();
951-
952- // Make sure tstate is in X0 for use in epilogue and here.
953- PhyLocation tstate = instr->getInput (0 )->getStackSlot ();
954- auto tstate_phys_reg = a64::x0;
955- as->ldr (
956- tstate_phys_reg,
957- arch::ptr_resolve (as, arch::fp, tstate.loc , arch::reg_scratch_0));
958-
959- // If we're skipping the initial send the send value is actually the first
960- // value to yield and so needs to go into X0 to be returned. Otherwise,
961- // put initial send value in X1, the same location future send values will
962- // be on resume.
963- PhyLocation send_value = instr->getInput (1 )->getStackSlot ();
964- const auto send_value_phys_reg = skip_initial_send ? X0 : X1 ;
965- as->ldr (
966- a64::x (send_value_phys_reg.loc ),
967- arch::ptr_resolve (as, arch::fp, send_value.loc , arch::reg_scratch_0));
968-
969- asmjit::Label yield_label = as->newLabel ();
970- if (skip_initial_send) {
971- as->b (yield_label);
972- } else {
973- // Setup call to JITRT_GenSend
974-
975- // Put tstate and the current generator into X3 and X0 respectively, and
976- // set finish_yield_from (X2) to 0. This register setup matches that when
977- // `resume_label` is reached from the resume entry.
978- auto gen_offs = offsetof (GenDataFooter, gen);
979- as->mov (a64::x3, tstate_phys_reg);
980- as->ldr (a64::x0, arch::ptr_offset (arch::fp, gen_offs));
981- as->mov (a64::x2, a64::xzr);
874+ #if PY_VERSION_HEX < 0x030C0000
875+ // On 3.10, for yield-from yield points, store the finish_yield_from arg
876+ // (X2 from resume entry) into GenDataFooter so the subsequent Send
877+ // instruction can load it.
878+ if (instr->isInYieldFromContext ()) {
879+ auto fyf_offset = offsetof (GenDataFooter, finishYieldFrom);
880+ as->str (
881+ a64::x2,
882+ arch::ptr_resolve (as, arch::fp, fyf_offset, arch::reg_scratch_0));
982883 }
884+ #endif
983885
984- // Resumed execution begins here
985- auto resume_label = as->newLabel ();
986- as->bind (resume_label);
987-
988- // Save tstate from resume to callee-saved reigster.
989- as->mov (a64::x19, a64::x3);
990-
991- // 'send_value', and 'finish_yield_from' will already be in X1 and X3
992- // respectively, either from code above on initial start or from resume entry
993- // point args.
994-
995- // Load sub-iterator into X0
996- PhyLocation iter_slot = instr->getInput (2 )->getStackSlot ();
997- as->ldr (
998- a64::x0,
999- arch::ptr_resolve (as, arch::fp, iter_slot.loc , arch::reg_scratch_0));
1000-
1001- uint64_t func = reinterpret_cast <uint64_t >(
1002- instr->isYieldFromHandleStopAsyncIteration ()
1003- ? JITRT_GenSendHandleStopAsyncIteration
1004- : JITRT_GenSend);
1005- emitCall (*env, func, instr);
1006- // Yielded or final result value now in X0. If the result was nullptr then
1007- // done will be set so we'll correctly jump to the following CheckExc.
1008- const auto yf_result_phys_reg = X0 ;
1009- const auto done_r = a64::x2;
1010-
1011- // Restore tstate from callee-saved register.
1012- as->mov (tstate_phys_reg, a64::x19);
1013-
1014- // If not done, jump to epilogue which will yield/return the value from
1015- // JITRT_GenSend in X0.
1016- asmjit::Label done_label = as->newLabel ();
1017- as->cbnz (done_r, done_label);
1018-
1019- as->bind (yield_label);
1020- // Arbitrary scratch register for use in emitStoreGenYieldPoint()
1021- auto scratch_r = arch::reg_scratch_0;
1022- emitStoreGenYieldPoint (as, env, instr, resume_label, arch::fp, scratch_r);
1023- as->b (env->exit_for_yield_label );
1024-
1025- as->bind (done_label);
1026- emitLoadResumedYieldInputs (as, instr, yf_result_phys_reg, tstate_phys_reg);
886+ // Sent in value is in x1, and tstate is in x3 from resume entry-point args
887+ emitLoadResumedYieldInputs (as, instr, X1 , a64::x3);
1027888#else
1028889 CINDER_UNSUPPORTED
1029890#endif
@@ -1837,28 +1698,6 @@ BEGIN_RULES(Instruction::kYieldInitial)
18371698 GEN (ANY , CALL_C (translateYieldInitial))
18381699END_RULES
18391700
1840- #if PY_VERSION_HEX < 0x030C0000
1841- BEGIN_RULES (Instruction::kYieldFrom )
1842- GEN (ANY , CALL_C (translateYieldFrom))
1843- END_RULES
1844- #else
1845- // In 3.12+ YieldFrom is a pseudo-op which is YieldValue plus enough
1846- // information to know which live value contains the target iterator. See
1847- // emitStoreGenYieldPoint() for where this is captured. The target iterator is
1848- // used for things like the result of reading gi_yieldfrom.
1849- BEGIN_RULES (Instruction::kYieldFrom )
1850- GEN (ANY , CALL_C (translateYieldValue))
1851- END_RULES
1852- #endif
1853-
1854- BEGIN_RULES (Instruction::kYieldFromSkipInitialSend )
1855- GEN (ANY , CALL_C (translateYieldFrom))
1856- END_RULES
1857-
1858- BEGIN_RULES (Instruction::kYieldFromHandleStopAsyncIteration )
1859- GEN (ANY , CALL_C (translateYieldFrom))
1860- END_RULES
1861-
18621701BEGIN_RULES (Instruction::kYieldValue )
18631702 GEN (ANY , CALL_C (translateYieldValue))
18641703END_RULES
@@ -3150,28 +2989,6 @@ BEGIN_RULES(Instruction::kYieldInitial)
31502989 GEN (ANY , CALL_C (translateYieldInitial))
31512990END_RULES
31522991
3153- #if PY_VERSION_HEX < 0x030C0000
3154- BEGIN_RULES (Instruction::kYieldFrom )
3155- GEN (ANY , CALL_C (translateYieldFrom))
3156- END_RULES
3157- #else
3158- // In 3.12+ YieldFrom is a pseudo-op which is YieldValue plus enough
3159- // information to know which live value contains the target iterator. See
3160- // emitStoreGenYieldPoint() for where this is captured. The target iterator is
3161- // used for things like the result of reading gi_yieldfrom.
3162- BEGIN_RULES (Instruction::kYieldFrom )
3163- GEN (ANY , CALL_C (translateYieldValue))
3164- END_RULES
3165- #endif
3166-
3167- BEGIN_RULES (Instruction::kYieldFromSkipInitialSend )
3168- GEN (ANY , CALL_C (translateYieldFrom))
3169- END_RULES
3170-
3171- BEGIN_RULES (Instruction::kYieldFromHandleStopAsyncIteration )
3172- GEN (ANY , CALL_C (translateYieldFrom))
3173- END_RULES
3174-
31752992BEGIN_RULES (Instruction::kYieldValue )
31762993 GEN (ANY , CALL_C (translateYieldValue))
31772994END_RULES
0 commit comments