Add encodings for CPU flags instructions.
Branch on flags: brif, brff, Compare integers to flags: ifcmp Compare floats to flags: ffcmp Convert flags to b1: trueif, trueff
This commit is contained in:
@@ -279,10 +279,15 @@ 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))
|
||||
enc_both(base.jump, r.jmpb, 0xeb)
|
||||
enc_both(base.jump, r.jmpd, 0xe9)
|
||||
|
||||
enc_both(base.brif, r.brib, 0x70)
|
||||
enc_both(base.brif, r.brid, 0x0f, 0x80)
|
||||
|
||||
# Not all float condition codes are legal, see `supported_floatccs`.
|
||||
enc_both(base.brff, r.brfb, 0x70)
|
||||
enc_both(base.brff, r.brfd, 0x0f, 0x80)
|
||||
|
||||
# Note that the tjccd opcode will be prefixed with 0x0f.
|
||||
enc_i32_i64(base.brz, r.tjccb, 0x74)
|
||||
@@ -313,6 +318,14 @@ I64.enc(base.trap, *r.trap(0x0f, 0x0b))
|
||||
# Comparisons
|
||||
#
|
||||
enc_i32_i64(base.icmp, r.icscc, 0x39)
|
||||
enc_i32_i64(base.ifcmp, r.rcmp, 0x39)
|
||||
|
||||
#
|
||||
# Convert flags to bool.
|
||||
#
|
||||
# This encodes `b1` as an 8-bit low register with the value 0 or 1.
|
||||
enc_both(base.trueif, r.seti_abcd, 0x0f, 0x90)
|
||||
enc_both(base.trueff, r.setf_abcd, 0x0f, 0x90)
|
||||
|
||||
#
|
||||
# Convert bool to int.
|
||||
@@ -416,3 +429,6 @@ enc_both(base.band_not.f64, r.fax, 0x0f, 0x55)
|
||||
# handled by legalization patterns.
|
||||
enc_both(base.fcmp.f32, r.fcscc, 0x0f, 0x2e)
|
||||
enc_both(base.fcmp.f64, r.fcscc, 0x66, 0x0f, 0x2e)
|
||||
|
||||
enc_both(base.ffcmp.f32, r.fcmp, 0x0f, 0x2e)
|
||||
enc_both(base.ffcmp.f64, r.fcmp, 0x66, 0x0f, 0x2e)
|
||||
|
||||
@@ -7,10 +7,11 @@ from cdsl.predicates import IsSignedInt, IsEqual, Or
|
||||
from cdsl.registers import RegClass
|
||||
from base.formats import Unary, UnaryImm, Binary, BinaryImm, MultiAry
|
||||
from base.formats import Trap, Call, IndirectCall, Store, Load
|
||||
from base.formats import IntCompare, FloatCompare
|
||||
from base.formats import Ternary, Jump, Branch, FuncAddr
|
||||
from base.formats import IntCompare, FloatCompare, IntCond, FloatCond
|
||||
from base.formats import Jump, Branch, BranchInt, BranchFloat
|
||||
from base.formats import Ternary, FuncAddr
|
||||
from base.formats import RegMove, RegSpill, RegFill
|
||||
from .registers import GPR, ABCD, FPR, GPR8, FPR8, StackGPR32, StackFPR32
|
||||
from .registers import GPR, ABCD, FPR, GPR8, FPR8, FLAG, StackGPR32, StackFPR32
|
||||
from .defs import supported_floatccs
|
||||
|
||||
try:
|
||||
@@ -250,6 +251,15 @@ class TailRecipe:
|
||||
assert name == obj.name, "Mismatched TailRecipe name: " + name
|
||||
|
||||
|
||||
def floatccs(iform):
|
||||
# type: (InstructionFormat) -> PredNode
|
||||
"""
|
||||
Return an instruction predicate that checks in `iform.cond` is one of the
|
||||
directly supported floating point condition codes.
|
||||
"""
|
||||
return Or(*(IsEqual(iform.cond, cc) for cc in supported_floatccs))
|
||||
|
||||
|
||||
# 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='')
|
||||
@@ -754,6 +764,100 @@ jmpd = TailRecipe(
|
||||
disp4(destination, func, sink);
|
||||
''')
|
||||
|
||||
brib = TailRecipe(
|
||||
'brib', BranchInt, size=1, ins=FLAG.eflags, outs=(),
|
||||
branch_range=8,
|
||||
emit='''
|
||||
PUT_OP(bits | icc2opc(cond), BASE_REX, sink);
|
||||
disp1(destination, func, sink);
|
||||
''')
|
||||
|
||||
brid = TailRecipe(
|
||||
'brid', BranchInt, size=4, ins=FLAG.eflags, outs=(),
|
||||
branch_range=32,
|
||||
emit='''
|
||||
PUT_OP(bits | icc2opc(cond), BASE_REX, sink);
|
||||
disp4(destination, func, sink);
|
||||
''')
|
||||
|
||||
brfb = TailRecipe(
|
||||
'brfb', BranchFloat, size=1, ins=FLAG.eflags, outs=(),
|
||||
branch_range=8,
|
||||
instp=floatccs(BranchFloat),
|
||||
emit='''
|
||||
PUT_OP(bits | fcc2opc(cond), BASE_REX, sink);
|
||||
disp1(destination, func, sink);
|
||||
''')
|
||||
|
||||
brfd = TailRecipe(
|
||||
'brfd', BranchFloat, size=4, ins=FLAG.eflags, outs=(),
|
||||
branch_range=32,
|
||||
instp=floatccs(BranchFloat),
|
||||
emit='''
|
||||
PUT_OP(bits | fcc2opc(cond), BASE_REX, sink);
|
||||
disp4(destination, func, sink);
|
||||
''')
|
||||
|
||||
#
|
||||
# Test flags and set a register.
|
||||
#
|
||||
# These setCC instructions only set the low 8 bits, and they can only write
|
||||
# ABCD registers without a REX prefix.
|
||||
#
|
||||
# Other instruction encodings accepting `b1` inputs have the same constraints
|
||||
# and only look at the low 8 bits of the input register.
|
||||
#
|
||||
|
||||
seti = TailRecipe(
|
||||
'seti', IntCond, size=1, ins=FLAG.eflags, outs=GPR,
|
||||
requires_prefix=True,
|
||||
emit='''
|
||||
PUT_OP(bits | icc2opc(cond), rex1(out_reg0), sink);
|
||||
modrm_r_bits(out_reg0, bits, sink);
|
||||
''')
|
||||
seti_abcd = TailRecipe(
|
||||
'seti_abcd', IntCond, size=1, ins=FLAG.eflags, outs=ABCD,
|
||||
when_prefixed=seti,
|
||||
emit='''
|
||||
PUT_OP(bits | icc2opc(cond), rex1(out_reg0), sink);
|
||||
modrm_r_bits(out_reg0, bits, sink);
|
||||
''')
|
||||
|
||||
setf = TailRecipe(
|
||||
'setf', FloatCond, size=1, ins=FLAG.eflags, outs=GPR,
|
||||
requires_prefix=True,
|
||||
emit='''
|
||||
PUT_OP(bits | fcc2opc(cond), rex1(out_reg0), sink);
|
||||
modrm_r_bits(out_reg0, bits, sink);
|
||||
''')
|
||||
setf_abcd = TailRecipe(
|
||||
'setf_abcd', FloatCond, size=1, ins=FLAG.eflags, outs=ABCD,
|
||||
when_prefixed=setf,
|
||||
emit='''
|
||||
PUT_OP(bits | fcc2opc(cond), rex1(out_reg0), sink);
|
||||
modrm_r_bits(out_reg0, bits, sink);
|
||||
''')
|
||||
|
||||
#
|
||||
# Compare and set flags.
|
||||
#
|
||||
|
||||
# XX /r, MR form. Compare two GPR registers and set flags.
|
||||
rcmp = TailRecipe(
|
||||
'rcmp', Binary, size=1, ins=(GPR, GPR), outs=FLAG.eflags,
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||
modrm_rr(in_reg0, in_reg1, sink);
|
||||
''')
|
||||
|
||||
# XX /r, RM form. Compare two FPR registers and set flags.
|
||||
fcmp = TailRecipe(
|
||||
'fcmp', Binary, size=1, ins=(FPR, FPR), outs=FLAG.eflags,
|
||||
emit='''
|
||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||
modrm_rr(in_reg1, in_reg0, sink);
|
||||
''')
|
||||
|
||||
# Test-and-branch.
|
||||
#
|
||||
# This recipe represents the macro fusion of a test and a conditional branch.
|
||||
@@ -926,8 +1030,7 @@ icscc = TailRecipe(
|
||||
# The omission of a `when_prefixed` alternative is deliberate here.
|
||||
fcscc = TailRecipe(
|
||||
'fcscc', FloatCompare, size=1 + 3, ins=(FPR, FPR), outs=ABCD,
|
||||
instp=Or(*(IsEqual(FloatCompare.cond, cc)
|
||||
for cc in supported_floatccs)),
|
||||
instp=floatccs(FloatCompare),
|
||||
emit='''
|
||||
// Comparison instruction.
|
||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||
|
||||
Reference in New Issue
Block a user