Add long-range encodings for conditional branches.

The brz and brnz instructions get support for 32-bit jump displacements
for long range branches.

Also change the way branch ranges are specified on tail recipes for the
Intel instructions. All branch displacements are relative to the end of
the instruction, so just compute the branch range origin as the
instruction size instead of trying to specify it in the tail recipe
definitions.
This commit is contained in:
Jakob Stoklund Olesen
2017-09-29 13:18:29 -07:00
parent 50ccd000a9
commit 86e22e7de5
2 changed files with 56 additions and 16 deletions

View File

@@ -298,18 +298,18 @@ I32.enc(base.jump, *r.jmpd(0xe9))
I64.enc(base.jump, *r.jmpb(0xeb)) I64.enc(base.jump, *r.jmpb(0xeb))
I64.enc(base.jump, *r.jmpd(0xe9)) I64.enc(base.jump, *r.jmpd(0xe9))
# Note that the tjccd opcode will be prefixed with 0x0f.
enc_i32_i64(base.brz, r.tjccb, 0x74) enc_i32_i64(base.brz, r.tjccb, 0x74)
enc_i32_i64(base.brz, r.tjccd, 0x84)
enc_i32_i64(base.brnz, r.tjccb, 0x75) enc_i32_i64(base.brnz, r.tjccb, 0x75)
enc_i32_i64(base.brnz, r.tjccd, 0x85)
# Branch on a b1 value in a register only looks at the low 8 bits. See also # Branch on a b1 value in a register only looks at the low 8 bits. See also
# bint encodings below. # bint encodings below.
I32.enc(base.brz.b1, *r.t8jccb_abcd(0x74)) enc_flt(base.brz.b1, r.t8jccb_abcd, 0x74)
I64.enc(base.brz.b1, *r.t8jccb_abcd.rex(0x74)) enc_flt(base.brz.b1, r.t8jccd_abcd, 0x84)
I64.enc(base.brz.b1, *r.t8jccb_abcd(0x74)) enc_flt(base.brnz.b1, r.t8jccb_abcd, 0x75)
I32.enc(base.brnz.b1, *r.t8jccb_abcd(0x75)) enc_flt(base.brnz.b1, r.t8jccd_abcd, 0x85)
I64.enc(base.brnz.b1, *r.t8jccb_abcd.rex(0x75))
I64.enc(base.brnz.b1, *r.t8jccb_abcd(0x75))
# #
# Trap as ud2 # Trap as ud2

View File

@@ -131,7 +131,7 @@ class TailRecipe:
size, # type: int size, # type: int
ins, # type: ConstraintSeq ins, # type: ConstraintSeq
outs, # type: ConstraintSeq outs, # type: ConstraintSeq
branch_range=None, # type: BranchRange branch_range=None, # type: int
instp=None, # type: PredNode instp=None, # type: PredNode
isap=None, # type: PredNode isap=None, # type: PredNode
emit=None # type: str emit=None # type: str
@@ -159,14 +159,21 @@ class TailRecipe:
rrr = kwargs.get('rrr', 0) rrr = kwargs.get('rrr', 0)
w = kwargs.get('w', 0) w = kwargs.get('w', 0)
name, bits = decode_ops(ops, rrr, w) name, bits = decode_ops(ops, rrr, w)
size = len(ops) + self.size
# All branch ranges are relative to the end of the instruction.
branch_range = None # type BranchRange
if self.branch_range is not None:
branch_range = (size, self.branch_range)
if name not in self.recipes: if name not in self.recipes:
recipe = EncRecipe( recipe = EncRecipe(
name + self.name, name + self.name,
self.format, self.format,
len(ops) + self.size, size,
ins=self.ins, ins=self.ins,
outs=self.outs, outs=self.outs,
branch_range=self.branch_range, branch_range=branch_range,
instp=self.instp, instp=self.instp,
isap=self.isap, isap=self.isap,
emit=replace_put_op(self.emit, name)) emit=replace_put_op(self.emit, name))
@@ -193,14 +200,21 @@ class TailRecipe:
w = kwargs.get('w', 0) w = kwargs.get('w', 0)
name, bits = decode_ops(ops, rrr, w) name, bits = decode_ops(ops, rrr, w)
name = 'Rex' + name name = 'Rex' + name
size = 1 + len(ops) + self.size
# All branch ranges are relative to the end of the instruction.
branch_range = None # type BranchRange
if self.branch_range is not None:
branch_range = (size, self.branch_range)
if name not in self.recipes: if name not in self.recipes:
self.recipes[name] = EncRecipe( self.recipes[name] = EncRecipe(
name + self.name, name + self.name,
self.format, self.format,
1 + len(ops) + self.size, size,
ins=self.ins, ins=self.ins,
outs=self.outs, outs=self.outs,
branch_range=self.branch_range, branch_range=branch_range,
instp=self.instp, instp=self.instp,
isap=self.isap, isap=self.isap,
emit=replace_put_op(self.emit, name)) emit=replace_put_op(self.emit, name))
@@ -656,7 +670,7 @@ ret = TailRecipe(
# #
jmpb = TailRecipe( jmpb = TailRecipe(
'jmpb', Jump, size=1, ins=(), outs=(), 'jmpb', Jump, size=1, ins=(), outs=(),
branch_range=(2, 8), branch_range=8,
emit=''' emit='''
PUT_OP(bits, BASE_REX, sink); PUT_OP(bits, BASE_REX, sink);
disp1(destination, func, sink); disp1(destination, func, sink);
@@ -664,7 +678,7 @@ jmpb = TailRecipe(
jmpd = TailRecipe( jmpd = TailRecipe(
'jmpd', Jump, size=4, ins=(), outs=(), 'jmpd', Jump, size=4, ins=(), outs=(),
branch_range=(5, 32), branch_range=32,
emit=''' emit='''
PUT_OP(bits, BASE_REX, sink); PUT_OP(bits, BASE_REX, sink);
disp4(destination, func, sink); disp4(destination, func, sink);
@@ -685,7 +699,7 @@ jmpd = TailRecipe(
# Bits 8-15 control the test instruction which always has opcode byte 0x85. # Bits 8-15 control the test instruction which always has opcode byte 0x85.
tjccb = TailRecipe( tjccb = TailRecipe(
'tjccb', Branch, size=1 + 2, ins=GPR, outs=(), 'tjccb', Branch, size=1 + 2, ins=GPR, outs=(),
branch_range=(2, 8), branch_range=8,
emit=''' emit='''
// test r, r. // test r, r.
PUT_OP((bits & 0xff00) | 0x85, rex2(in_reg0, in_reg0), sink); PUT_OP((bits & 0xff00) | 0x85, rex2(in_reg0, in_reg0), sink);
@@ -695,13 +709,26 @@ tjccb = TailRecipe(
disp1(destination, func, sink); disp1(destination, func, sink);
''') ''')
tjccd = TailRecipe(
'tjccd', Branch, size=1 + 6, ins=GPR, outs=(),
branch_range=32,
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(0x0f);
sink.put1(bits as u8);
disp4(destination, func, sink);
''')
# 8-bit test-and-branch. # 8-bit test-and-branch.
# #
# Same as tjccb, but only looks at the low 8 bits of the register, for b1 # Same as tjccb, but only looks at the low 8 bits of the register, for b1
# types. # types.
t8jccb_abcd = TailRecipe( t8jccb_abcd = TailRecipe(
't8jccb_abcd', Branch, size=1 + 2, ins=ABCD, outs=(), 't8jccb_abcd', Branch, size=1 + 2, ins=ABCD, outs=(),
branch_range=(2, 8), branch_range=8,
emit=''' emit='''
// test8 r, r. // test8 r, r.
PUT_OP(0x84, rex2(in_reg0, in_reg0), sink); PUT_OP(0x84, rex2(in_reg0, in_reg0), sink);
@@ -711,6 +738,19 @@ t8jccb_abcd = TailRecipe(
disp1(destination, func, sink); disp1(destination, func, sink);
''') ''')
t8jccd_abcd = TailRecipe(
't8jccd_abcd', Branch, size=1 + 6, ins=ABCD, outs=(),
branch_range=32,
emit='''
// test8 r, r.
PUT_OP(0x84, rex2(in_reg0, in_reg0), sink);
modrm_rr(in_reg0, in_reg0, sink);
// Jcc instruction.
sink.put1(0x0f);
sink.put1(bits as u8);
disp4(destination, func, sink);
''')
# Comparison that produces a `b1` result in a GPR. # Comparison that produces a `b1` result in a GPR.
# #
# This is a macro of a `cmp` instruction followed by a `setCC` instruction. # This is a macro of a `cmp` instruction followed by a `setCC` instruction.