定期ミートアップ #47
yjit-benchへの対応作業
return/break/nextの実装
whileなどのループ内ではreturnはただのreturn、break/nextは単なるGOTO
code:text
❯ cargo run --features emit-bc -- -e "while true do return; break; next end"
+:00000 init_method reg:1 arg:0 req:0 opt:0 rest:false block:None stack_offset:4
+:00001 loop_start counter=0 jit-addr=0000000000000000
:00002 %1 = literaltrue
:00003 condnotbr %1 =>:00011
:00004 %1 = nil
:00005 ret %1 # return
:00006 %1 = nil
:00007 br =>:00012 # break
:00008 %1 = nil
:00009 br =>:00001 # next
:00010 br =>:00001
+:00011 %1 = nil
+:00012 loop_end
:00013 ret %1
ブロック内では
code:Ruby
def f
5.times do |x|
next # ブロックを抜ける
break # ブロックを呼んだメソッド(times)を抜ける
return # ブロックが所属するメソッド(f)を抜ける
end
end
code:text
+:00000 init_method reg:2 arg:1 req:1 opt:0 rest:false block:None stack_offset:5
:00001 %2 = nil
:00002 ret %2 # next
:00003 %2 = nil
:00004 break %2 # break
:00005 %2 = nil
:00006 method_ret %2 # return
https://gyazo.com/f161f7172488de2c40b37364ab0dfeba
https://gyazo.com/7b0173e7951393c479adae6a08e8a48b
code:Rust
fn block_break(&mut self) {
monoasm! { self.jit,
movq rdi, rbx;
movq rdi, rdi; // rdi <- caller's CFP
lea rbp, rdi + (BP_PREV_CFP);
};
}
fn method_return(&mut self) {
monoasm! { self.jit,
subq r14, (LBP_OUTER); // r14 <- DFP
loop1: // traverse scope link
cmpq r14, 0;
je cont1;
movq r14, r14;
jmp loop1;
cont1:
addq r14, (LBP_OUTER); // r14 <- outermost lfp
movq rdi, rbx; // rdi <- current CFP
loop2: // traverse call stack
cmpq rdi - ((BP_LFP - BP_PREV_CFP) as i32), r14;
je cont2;
movq rdi, rdi;
jmp loop2;
cont2:
lea rbp, rdi + (BP_PREV_CFP);
}
}
CRubyでは
code:Ruby
def foo
1.times {
return
break
next
redo
}
end
code:text
| catch type: break st: 0000 ed: 0004 sp: 0000 cont: 0004
| == disasm: #<ISeq:block in foo@<compiled>:3 (3,10)-(8,3)> (catch: true)
| == catch table
| | catch type: redo st: 0001 ed: 0014 sp: 0000 cont: 0001
| | catch type: next st: 0001 ed: 0014 sp: 0000 cont: 0014
| |------------------------------------------------------------------------
| 0000 nop ( 3)Bc
| 0001 putnil ( 4)Li
| 0002 throw 1
| 0004 pop
| 0005 putnil ( 5)Li
| 0006 throw 2
| 0008 pop
| 0009 putnil ( 6)Li
| 0010 leave ( 8)Br
| 0011 jump 1 ( 7)Li
| 0013 putnil
| 0014 leave ( 8)Br
ブロック内からのreturn, breakはthrow命令になっている。
redoは単に先頭へGOTOするだけ。
x86のparity flag
PF (bit 2) Parity flag — Set if the least-significant byte of the result contains an even number of 1 bits; cleared otherwise.
何に使うの?これ
UCOMISD—Unordered Compare Scalar Double Precision Floating-Point Values and Set EFLAGS
Operation
(V)UCOMISD (all versions)
RESULT := UnorderedCompare(DEST63:0 <> SRC63:0) {
(* Set EFLAGS *) CASE (RESULT) OF
UNORDERED: ZF,PF,CF := 111;
GREATER_THAN: ZF,PF,CF := 000;
LESS_THAN: ZF,PF,CF := 001;
EQUAL: ZF,PF,CF := 100;
ESAC;
OF, AF, SF := 0; }
浮動小数点数レジスタの比較命令でUnordered(どちらかがNaN)だった場合にPFがセットされる