Add Intel encodings for the icmp instruction.
This instruction returns a `b1` value which is represented as the output of a setCC instruction which is the low 8 bits of a GPR register. Use a cmp+setCC macro recipe to encode this. That is not ideal, but we can't represent CPU flags yet.
This commit is contained in:
@@ -11,7 +11,8 @@ from .immediates import intcc
|
||||
from .instructions import iadd, iadd_cout, iadd_cin, iadd_carry, iadd_imm
|
||||
from .instructions import isub, isub_bin, isub_bout, isub_borrow
|
||||
from .instructions import band, bor, bxor, isplit, iconcat
|
||||
from .instructions import icmp, iconst, bint
|
||||
from .instructions import icmp, icmp_imm
|
||||
from .instructions import iconst, bint
|
||||
from cdsl.ast import Var
|
||||
from cdsl.xform import Rtl, XFormGroup
|
||||
|
||||
@@ -53,6 +54,7 @@ yl = Var('yl')
|
||||
yh = Var('yh')
|
||||
al = Var('al')
|
||||
ah = Var('ah')
|
||||
cc = Var('cc')
|
||||
|
||||
narrow.legalize(
|
||||
a << iadd(x, y),
|
||||
@@ -135,10 +137,17 @@ expand.legalize(
|
||||
b << bor(b1, b2)
|
||||
))
|
||||
|
||||
# Expansions for immediates that are too large.
|
||||
# Expansions for immediate operands that are out of range.
|
||||
expand.legalize(
|
||||
a << iadd_imm(x, y),
|
||||
Rtl(
|
||||
a1 << iconst(y),
|
||||
a << iadd(x, a1)
|
||||
))
|
||||
|
||||
expand.legalize(
|
||||
a << icmp_imm(cc, x, y),
|
||||
Rtl(
|
||||
a1 << iconst(y),
|
||||
a << icmp(cc, x, a1)
|
||||
))
|
||||
|
||||
@@ -174,3 +174,11 @@ 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))
|
||||
|
||||
#
|
||||
# Comparisons
|
||||
#
|
||||
I32.enc(base.icmp.i32, *r.icscc(0x39))
|
||||
I64.enc(base.icmp.i64, *r.icscc.rex(0x39, w=1))
|
||||
I64.enc(base.icmp.i32, *r.icscc.rex(0x39))
|
||||
I64.enc(base.icmp.i32, *r.icscc(0x39))
|
||||
|
||||
@@ -6,6 +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 IntCompare
|
||||
from base.formats import RegMove, Ternary, Jump, Branch
|
||||
from .registers import GPR, ABCD
|
||||
|
||||
@@ -464,3 +465,44 @@ tjccb = TailRecipe(
|
||||
sink.put1(bits as u8);
|
||||
disp1(destination, func, sink);
|
||||
''')
|
||||
|
||||
# Comparison that produces a `b1` result in a GPR.
|
||||
#
|
||||
# This is a macro of a `cmp` instruction followed by a `setCC` instruction.
|
||||
# This is not a great solution because:
|
||||
#
|
||||
# - The cmp+setcc combination is not recognized by CPU's macro fusion.
|
||||
# - The 64-bit encoding has issues with REX prefixes. The `cmp` and `setCC`
|
||||
# instructions may need a REX independently.
|
||||
# - Modeling CPU flags in the type system would be better.
|
||||
#
|
||||
# Since the `setCC` instructions only write an 8-bit register, we use that as
|
||||
# our `b1` representation: A `b1` value is represented as a GPR where the low 8
|
||||
# bits are known to be 0 or 1. The high bits are undefined.
|
||||
#
|
||||
# This bandaid macro doesn't support a REX prefix for the final `setCC`
|
||||
# instruction, so it is limited to the `ABCD` register class for booleans.
|
||||
icscc = TailRecipe(
|
||||
'cscc', IntCompare, size=1 + 3, ins=(GPR, GPR), outs=ABCD,
|
||||
emit='''
|
||||
// Comparison instruction.
|
||||
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||
modrm_rr(in_reg0, in_reg1, sink);
|
||||
// `setCC` instruction, no REX.
|
||||
use ir::condcodes::IntCC::*;
|
||||
let setcc = match cond {
|
||||
Equal => 0x94,
|
||||
NotEqual => 0x95,
|
||||
SignedLessThan => 0x9c,
|
||||
SignedGreaterThanOrEqual => 0x9d,
|
||||
SignedGreaterThan => 0x9f,
|
||||
SignedLessThanOrEqual => 0x9e,
|
||||
UnsignedLessThan => 0x92,
|
||||
UnsignedGreaterThanOrEqual => 0x93,
|
||||
UnsignedGreaterThan => 0x97,
|
||||
UnsignedLessThanOrEqual => 0x96,
|
||||
};
|
||||
sink.put1(0x0f);
|
||||
sink.put1(setcc);
|
||||
modrm_rr(out_reg0, 0, sink);
|
||||
''')
|
||||
|
||||
Reference in New Issue
Block a user