Add encodings for Intel dynamic shift instructions.
These instructions have a fixed register constraint; the shift amount is passed in CL. Add meta language syntax so a fixed register can be specified as "GPR.rcx".
This commit is contained in:
@@ -19,5 +19,20 @@ ebb0:
|
|||||||
; asm: addl %ecx, %esi
|
; asm: addl %ecx, %esi
|
||||||
[-,%rsi] v11 = iadd v2, v1 ; bin: 01 ce
|
[-,%rsi] v11 = iadd v2, v1 ; bin: 01 ce
|
||||||
|
|
||||||
|
; Dynamic shifts take the shift amount in %rcx.
|
||||||
|
|
||||||
|
; asm: shll %cl, %esi
|
||||||
|
[-,%rsi] v12 = ishl v2, v1 ; bin: d3 e6
|
||||||
|
; asm: shll %cl, %ecx
|
||||||
|
[-,%rcx] v13 = ishl v1, v1 ; bin: d3 e1
|
||||||
|
; asm: shrl %cl, %esi
|
||||||
|
[-,%rsi] v14 = ushr v2, v1 ; bin: d3 ee
|
||||||
|
; asm: shrl %cl, %ecx
|
||||||
|
[-,%rcx] v15 = ushr v1, v1 ; bin: d3 e9
|
||||||
|
; asm: sarl %cl, %esi
|
||||||
|
[-,%rsi] v16 = sshr v2, v1 ; bin: d3 fe
|
||||||
|
; asm: sarl %cl, %ecx
|
||||||
|
[-,%rcx] v17 = sshr v1, v1 ; bin: d3 f9
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ register bank.
|
|||||||
|
|
||||||
A register bank consists of a number of *register units* which are the smallest
|
A register bank consists of a number of *register units* which are the smallest
|
||||||
indivisible units of allocation and interference. A register unit doesn't
|
indivisible units of allocation and interference. A register unit doesn't
|
||||||
necesarily correspond to a particular number of bits in a register, it is more
|
necessarily correspond to a particular number of bits in a register, it is more
|
||||||
like a placeholder that can be used to determine of a register is taken or not.
|
like a placeholder that can be used to determine of a register is taken or not.
|
||||||
|
|
||||||
The register allocator works with *register classes* which can allocate one or
|
The register allocator works with *register classes* which can allocate one or
|
||||||
more register units at a time. A register class allocates more than one
|
more register units at a time. A register class allocates more than one
|
||||||
register unit at a time when its registers are composed of smaller alocatable
|
register unit at a time when its registers are composed of smaller allocatable
|
||||||
units. For example, the ARM double precision floating point registers are
|
units. For example, the ARM double precision floating point registers are
|
||||||
composed of two single precision registers.
|
composed of two single precision registers.
|
||||||
"""
|
"""
|
||||||
@@ -151,6 +151,18 @@ class RegBank(object):
|
|||||||
# sub-class.
|
# sub-class.
|
||||||
rc2.subclasses.append(rc1)
|
rc2.subclasses.append(rc1)
|
||||||
|
|
||||||
|
def unit_by_name(self, name):
|
||||||
|
# type: (str) -> int
|
||||||
|
"""
|
||||||
|
Get a register unit in this bank by name.
|
||||||
|
"""
|
||||||
|
if name in self.names:
|
||||||
|
r = self.names.index(name)
|
||||||
|
elif name.startswith(self.prefix):
|
||||||
|
r = int(name[len(self.prefix):])
|
||||||
|
assert r < self.units, 'Invalid register name: ' + name
|
||||||
|
return self.first_unit + r
|
||||||
|
|
||||||
|
|
||||||
class RegClass(object):
|
class RegClass(object):
|
||||||
"""
|
"""
|
||||||
@@ -242,6 +254,15 @@ class RegClass(object):
|
|||||||
|
|
||||||
return RegClass(self.bank, count=c, width=w, start=s)
|
return RegClass(self.bank, count=c, width=w, start=s)
|
||||||
|
|
||||||
|
def __getattr__(self, attr):
|
||||||
|
# type: (str) -> Register
|
||||||
|
"""
|
||||||
|
Get a specific register in the class by name.
|
||||||
|
|
||||||
|
For example: `GPR.r5`.
|
||||||
|
"""
|
||||||
|
return Register(self, self.bank.unit_by_name(attr))
|
||||||
|
|
||||||
def mask(self):
|
def mask(self):
|
||||||
# type: () -> List[int]
|
# type: () -> List[int]
|
||||||
"""
|
"""
|
||||||
@@ -298,8 +319,8 @@ class Register(object):
|
|||||||
Specific registers are used to describe constraints on instructions where
|
Specific registers are used to describe constraints on instructions where
|
||||||
some operands must use a fixed register.
|
some operands must use a fixed register.
|
||||||
|
|
||||||
Register objects should be created using the indexing syntax on the
|
Register instances can be created with the constructor, or accessed as
|
||||||
register class.
|
attributes on the register class: `GPR.rcx`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, rc, unit):
|
def __init__(self, rc, unit):
|
||||||
# type: (RegClass, int) -> None
|
# type: (RegClass, int) -> None
|
||||||
|
|||||||
@@ -4,7 +4,14 @@ Intel Encodings.
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
from base import instructions as base
|
from base import instructions as base
|
||||||
from .defs import I32
|
from .defs import I32
|
||||||
from .recipes import Op1rr
|
from .recipes import Op1rr, Op1rc
|
||||||
from .recipes import OP
|
from .recipes import OP
|
||||||
|
|
||||||
I32.enc(base.iadd.i32, Op1rr, OP(0x01))
|
I32.enc(base.iadd.i32, Op1rr, OP(0x01))
|
||||||
|
|
||||||
|
# 32-bit shifts and rotates.
|
||||||
|
# Note that the dynamic shift amount is only masked by 5 or 6 bits; the 8-bit
|
||||||
|
# and 16-bit shifts would need explicit masking.
|
||||||
|
I32.enc(base.ishl.i32.i32, Op1rc, OP(0xd3, rrr=4))
|
||||||
|
I32.enc(base.ushr.i32.i32, Op1rc, OP(0xd3, rrr=5))
|
||||||
|
I32.enc(base.sshr.i32.i32, Op1rc, OP(0xd3, rrr=7))
|
||||||
|
|||||||
@@ -65,3 +65,6 @@ def OP(op, pp=0, mm=0, rrr=0, w=0):
|
|||||||
|
|
||||||
# XX /r
|
# XX /r
|
||||||
Op1rr = EncRecipe('Op1rr', Binary, size=2, ins=(GPR, GPR), outs=0)
|
Op1rr = EncRecipe('Op1rr', Binary, size=2, ins=(GPR, GPR), outs=0)
|
||||||
|
|
||||||
|
# XX /n with one arg in %rcx, for shifts.
|
||||||
|
Op1rc = EncRecipe('Op1rc', Binary, size=2, ins=(GPR, GPR.rcx), outs=0)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ fn put_op1<CS: CodeSink + ?Sized>(bits: u16, sink: &mut CS) {
|
|||||||
sink.put1(bits as u8);
|
sink.put1(bits as u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emit a ModR/M byte for reg-reg operands.
|
||||||
fn modrm_rr<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS) {
|
fn modrm_rr<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS) {
|
||||||
let reg = reg as u8 & 7;
|
let reg = reg as u8 & 7;
|
||||||
let rm = rm as u8 & 7;
|
let rm = rm as u8 & 7;
|
||||||
@@ -22,6 +23,16 @@ fn modrm_rr<CS: CodeSink + ?Sized>(rm: RegUnit, reg: RegUnit, sink: &mut CS) {
|
|||||||
sink.put1(b);
|
sink.put1(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Emit a ModR/M byte where the reg bits are part of the opcode.
|
||||||
|
fn modrm_r_bits<CS: CodeSink + ?Sized>(rm: RegUnit, bits: u16, sink: &mut CS) {
|
||||||
|
let reg = (bits >> 12) as u8 & 7;
|
||||||
|
let rm = rm as u8 & 7;
|
||||||
|
let mut b = 0b11000000;
|
||||||
|
b |= reg << 3;
|
||||||
|
b |= rm;
|
||||||
|
sink.put1(b);
|
||||||
|
}
|
||||||
|
|
||||||
fn recipe_op1rr<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
|
fn recipe_op1rr<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
|
||||||
if let InstructionData::Binary { args, .. } = func.dfg[inst] {
|
if let InstructionData::Binary { args, .. } = func.dfg[inst] {
|
||||||
put_op1(func.encodings[inst].bits(), sink);
|
put_op1(func.encodings[inst].bits(), sink);
|
||||||
@@ -32,3 +43,13 @@ fn recipe_op1rr<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut C
|
|||||||
panic!("Expected Binary format: {:?}", func.dfg[inst]);
|
panic!("Expected Binary format: {:?}", func.dfg[inst]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn recipe_op1rc<CS: CodeSink + ?Sized>(func: &Function, inst: Inst, sink: &mut CS) {
|
||||||
|
if let InstructionData::Binary { args, .. } = func.dfg[inst] {
|
||||||
|
let bits = func.encodings[inst].bits();
|
||||||
|
put_op1(bits, sink);
|
||||||
|
modrm_r_bits(func.locations[args[0]].unwrap_reg(), bits, sink);
|
||||||
|
} else {
|
||||||
|
panic!("Expected Binary format: {:?}", func.dfg[inst]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user