Add Intel encodings for jump and branch instructions.
Just implement jump, brz, and brnz as needed for WebAssembly.
This commit is contained in:
@@ -156,3 +156,21 @@ I32.enc(base.call, *r.call_id(0xe8))
|
||||
I32.enc(base.call_indirect.i32, *r.call_r(0xff, rrr=2))
|
||||
I32.enc(base.x_return, *r.ret(0xc3))
|
||||
I64.enc(base.x_return, *r.ret(0xc3))
|
||||
|
||||
#
|
||||
# Branches
|
||||
#
|
||||
I32.enc(base.jump, *r.jmpb(0xeb))
|
||||
I32.enc(base.jump, *r.jmpd(0xe9))
|
||||
I64.enc(base.jump, *r.jmpb(0xeb))
|
||||
I64.enc(base.jump, *r.jmpd(0xe9))
|
||||
|
||||
I32.enc(base.brz.i32, *r.tjccb(0x74))
|
||||
I64.enc(base.brz.i64, *r.tjccb.rex(0x74, w=1))
|
||||
I64.enc(base.brz.i32, *r.tjccb.rex(0x74))
|
||||
I64.enc(base.brz.i32, *r.tjccb(0x74))
|
||||
|
||||
I32.enc(base.brnz.i32, *r.tjccb(0x75))
|
||||
I64.enc(base.brnz.i64, *r.tjccb.rex(0x75, w=1))
|
||||
I64.enc(base.brnz.i32, *r.tjccb.rex(0x75))
|
||||
I64.enc(base.brnz.i32, *r.tjccb(0x75))
|
||||
|
||||
@@ -6,7 +6,7 @@ from cdsl.isa import EncRecipe
|
||||
from cdsl.predicates import IsSignedInt, IsEqual
|
||||
from base.formats import Unary, UnaryImm, Binary, BinaryImm, MultiAry
|
||||
from base.formats import Call, IndirectCall, Store, Load
|
||||
from base.formats import RegMove, Ternary
|
||||
from base.formats import RegMove, Ternary, Jump, Branch
|
||||
from .registers import GPR, ABCD
|
||||
|
||||
try:
|
||||
@@ -420,3 +420,47 @@ ret = TailRecipe(
|
||||
emit='''
|
||||
PUT_OP(bits, BASE_REX, sink);
|
||||
''')
|
||||
|
||||
#
|
||||
# Branches
|
||||
#
|
||||
jmpb = TailRecipe(
|
||||
'jmpb', Jump, size=1, ins=(), outs=(),
|
||||
branch_range=(2, 8),
|
||||
emit='''
|
||||
PUT_OP(bits, BASE_REX, sink);
|
||||
disp1(destination, func, sink);
|
||||
''')
|
||||
|
||||
jmpd = TailRecipe(
|
||||
'jmpd', Jump, size=4, ins=(), outs=(),
|
||||
branch_range=(5, 32),
|
||||
emit='''
|
||||
PUT_OP(bits, BASE_REX, sink);
|
||||
disp4(destination, func, sink);
|
||||
''')
|
||||
|
||||
# Test-and-branch.
|
||||
#
|
||||
# This recipe represents the macro fusion of a test and a conditional branch.
|
||||
# This serves two purposes:
|
||||
#
|
||||
# 1. Guarantee that the test and branch get scheduled next to each other so
|
||||
# macro fusion is guaranteed to be possible.
|
||||
# 2. Hide the status flags from Cretonne which doesn't currently model flags.
|
||||
#
|
||||
# The encoding bits affect both the test and the branch instruction:
|
||||
#
|
||||
# Bits 0-7 are the Jcc opcode.
|
||||
# Bits 8-15 control the test instruction which always has opcode byte 0x85.
|
||||
tjccb = TailRecipe(
|
||||
'tjcc', Branch, size=1 + 2, ins=GPR, outs=(),
|
||||
branch_range=(2, 8),
|
||||
emit='''
|
||||
// test r, r.
|
||||
PUT_OP((bits & 0xff00) | 0x85, rex2(in_reg0, in_reg0), sink);
|
||||
modrm_rr(in_reg0, in_reg0, sink);
|
||||
// Jcc instruction.
|
||||
sink.put1(bits as u8);
|
||||
disp1(destination, func, sink);
|
||||
''')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Emitting binary Intel machine code.
|
||||
|
||||
use binemit::{CodeSink, Reloc, bad_encoding};
|
||||
use ir::{Function, Inst, InstructionData};
|
||||
use ir::{Function, Inst, Ebb, InstructionData};
|
||||
use isa::RegUnit;
|
||||
use regalloc::RegDiversions;
|
||||
|
||||
@@ -169,3 +169,15 @@ fn modrm_disp32<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS)
|
||||
b |= rm;
|
||||
sink.put1(b);
|
||||
}
|
||||
|
||||
/// Emit a single-byte branch displacement to `destination`.
|
||||
fn disp1<CS: CodeSink + ?Sized>(destination: Ebb, func: &Function, sink: &mut CS) {
|
||||
let delta = func.offsets[destination].wrapping_sub(sink.offset() + 1);
|
||||
sink.put1(delta as u8);
|
||||
}
|
||||
|
||||
/// Emit a single-byte branch displacement to `destination`.
|
||||
fn disp4<CS: CodeSink + ?Sized>(destination: Ebb, func: &Function, sink: &mut CS) {
|
||||
let delta = func.offsets[destination].wrapping_sub(sink.offset() + 4);
|
||||
sink.put4(delta);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user