Implement jump tables (#453)
* Add 'jump_table_entry' and 'indirect_jump' instructions. * Update CodeSink to keep track of code size. Pretty up clif-util's disassembly output. * Only disassemble the machine portion of output. Pretty print the read-only data after it. * Update switch frontend code to use new br_table instruction w/ default.
This commit is contained in:
committed by
Dan Gohman
parent
de1d82b4ba
commit
79cea5e18b
@@ -507,6 +507,17 @@ enc_both(base.brz.b1, r.t8jccd_abcd, 0x84)
|
||||
enc_both(base.brnz.b1, r.t8jccb_abcd, 0x75)
|
||||
enc_both(base.brnz.b1, r.t8jccd_abcd, 0x85)
|
||||
|
||||
#
|
||||
# Jump tables
|
||||
#
|
||||
X86_64.enc(base.jump_table_entry.i64.any.any, *r.jt_entry.rex(0x63, w=1))
|
||||
X86_32.enc(base.jump_table_entry.i32.any.any, *r.jt_entry(0x8b))
|
||||
|
||||
X86_64.enc(base.jump_table_base.i64, *r.jt_base.rex(0x8d, w=1))
|
||||
X86_32.enc(base.jump_table_base.i32, *r.jt_base(0x8d))
|
||||
|
||||
enc_x86_64(base.indirect_jump_table_br.i64, r.indirect_jmp, 0xff, rrr=4)
|
||||
X86_32.enc(base.indirect_jump_table_br.i32, *r.indirect_jmp(0xff, rrr=4))
|
||||
#
|
||||
# Trap as ud2
|
||||
#
|
||||
|
||||
@@ -14,6 +14,7 @@ from base.formats import IntCompare, IntCompareImm, FloatCompare
|
||||
from base.formats import IntCond, FloatCond
|
||||
from base.formats import IntSelect, IntCondTrap, FloatCondTrap
|
||||
from base.formats import Jump, Branch, BranchInt, BranchFloat
|
||||
from base.formats import BranchTableEntry, BranchTableBase, IndirectJump
|
||||
from base.formats import Ternary, FuncAddr, UnaryGlobalValue
|
||||
from base.formats import RegMove, RegSpill, RegFill, CopySpecial
|
||||
from base.formats import LoadComplex, StoreComplex
|
||||
@@ -276,6 +277,18 @@ def floatccs(iform):
|
||||
return Or(*(IsEqual(iform.cond, cc) for cc in supported_floatccs))
|
||||
|
||||
|
||||
def valid_scale(iform):
|
||||
# type: (InstructionFormat) -> PredNode
|
||||
"""
|
||||
Return an instruction predicate that checks if `iform.imm` is a valid
|
||||
`scale` for a SIB byte.
|
||||
"""
|
||||
return Or(IsEqual(iform.imm, 1),
|
||||
IsEqual(iform.imm, 2),
|
||||
IsEqual(iform.imm, 4),
|
||||
IsEqual(iform.imm, 8))
|
||||
|
||||
|
||||
# A null unary instruction that takes a GPR register. Can be used for identity
|
||||
# copies and no-op conversions.
|
||||
null = EncRecipe('null', Unary, size=0, ins=GPR, outs=0, emit='')
|
||||
@@ -1473,6 +1486,38 @@ brfd = TailRecipe(
|
||||
disp4(destination, func, sink);
|
||||
''')
|
||||
|
||||
indirect_jmp = TailRecipe(
|
||||
'indirect_jmp', IndirectJump, size=1, ins=GPR, outs=(),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
PUT_OP(bits, rex1(in_reg0), sink);
|
||||
modrm_r_bits(in_reg0, bits, sink);
|
||||
''')
|
||||
|
||||
jt_entry = TailRecipe(
|
||||
'jt_entry', BranchTableEntry, size=2,
|
||||
ins=(GPR_DEREF_SAFE, GPR_ZERO_DEREF_SAFE),
|
||||
outs=(GPR),
|
||||
clobbers_flags=False,
|
||||
instp=valid_scale(BranchTableEntry),
|
||||
emit='''
|
||||
PUT_OP(bits, rex3(in_reg1, out_reg0, in_reg0), sink);
|
||||
modrm_sib(out_reg0, sink);
|
||||
sib(imm.trailing_zeros() as u8, in_reg0, in_reg1, sink);
|
||||
''')
|
||||
|
||||
jt_base = TailRecipe(
|
||||
'jt_base', BranchTableBase, size=5, ins=(), outs=(GPR),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
// No reloc is needed here as the jump table is emitted directly after
|
||||
// the function body.
|
||||
PUT_OP(bits, rex2(0, out_reg0), sink);
|
||||
modrm_riprel(out_reg0, sink);
|
||||
|
||||
jt_disp4(table, func, sink);
|
||||
''')
|
||||
|
||||
#
|
||||
# Test flags and set a register.
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user