Intel encodings for regspill and regfill.
These are always SP-based.
This commit is contained in:
@@ -185,6 +185,11 @@ ebb0:
|
|||||||
; asm: movd 1032(%esp), %xmm2
|
; asm: movd 1032(%esp), %xmm2
|
||||||
[-,%xmm2] v211 = fill v201 ; bin: 66 0f 6e 94 24 00000408
|
[-,%xmm2] v211 = fill v201 ; bin: 66 0f 6e 94 24 00000408
|
||||||
|
|
||||||
|
; asm: movd %xmm5, 1032(%rsp)
|
||||||
|
regspill v100, %xmm5 -> ss1 ; bin: 66 0f 7e ac 24 00000408
|
||||||
|
; asm: movd 1032(%rsp), %xmm5
|
||||||
|
regfill v100, ss1 -> %xmm5 ; bin: 66 0f 6e ac 24 00000408
|
||||||
|
|
||||||
; Comparisons.
|
; Comparisons.
|
||||||
;
|
;
|
||||||
; Only `supported_floatccs` are tested here. Others are handled by
|
; Only `supported_floatccs` are tested here. Others are handled by
|
||||||
@@ -388,6 +393,11 @@ ebb0:
|
|||||||
; asm: movq 1032(%esp), %xmm2
|
; asm: movq 1032(%esp), %xmm2
|
||||||
[-,%xmm2] v211 = fill v201 ; bin: f3 0f 7e 94 24 00000408
|
[-,%xmm2] v211 = fill v201 ; bin: f3 0f 7e 94 24 00000408
|
||||||
|
|
||||||
|
; asm: movq %xmm5, 1032(%rsp)
|
||||||
|
regspill v100, %xmm5 -> ss1 ; bin: 66 0f d6 ac 24 00000408
|
||||||
|
; asm: movq 1032(%rsp), %xmm5
|
||||||
|
regfill v100, ss1 -> %xmm5 ; bin: f3 0f 7e ac 24 00000408
|
||||||
|
|
||||||
; Comparisons.
|
; Comparisons.
|
||||||
;
|
;
|
||||||
; Only `supported_floatccs` are tested here. Others are handled by
|
; Only `supported_floatccs` are tested here. Others are handled by
|
||||||
|
|||||||
@@ -363,6 +363,11 @@ ebb0:
|
|||||||
; asm: movl 1032(%esp), %esi
|
; asm: movl 1032(%esp), %esi
|
||||||
[-,%rsi] v511 = fill v501 ; bin: 8b b4 24 00000408
|
[-,%rsi] v511 = fill v501 ; bin: 8b b4 24 00000408
|
||||||
|
|
||||||
|
; asm: movl %ecx, 1032(%esp)
|
||||||
|
regspill v1, %rcx -> ss1 ; bin: 89 8c 24 00000408
|
||||||
|
; asm: movl 1032(%esp), %ecx
|
||||||
|
regfill v1, ss1 -> %rcx ; bin: 8b 8c 24 00000408
|
||||||
|
|
||||||
; asm: testl %ecx, %ecx
|
; asm: testl %ecx, %ecx
|
||||||
; asm: je ebb1
|
; asm: je ebb1
|
||||||
brz v1, ebb1 ; bin: 85 c9 74 0e
|
brz v1, ebb1 ; bin: 85 c9 74 0e
|
||||||
|
|||||||
@@ -194,6 +194,11 @@ ebb0:
|
|||||||
; asm: movd 1032(%rsp), %xmm10
|
; asm: movd 1032(%rsp), %xmm10
|
||||||
[-,%xmm10] v211 = fill v201 ; bin: 66 44 0f 6e 94 24 00000408
|
[-,%xmm10] v211 = fill v201 ; bin: 66 44 0f 6e 94 24 00000408
|
||||||
|
|
||||||
|
; asm: movd %xmm5, 1032(%rsp)
|
||||||
|
regspill v100, %xmm5 -> ss1 ; bin: 66 0f 7e ac 24 00000408
|
||||||
|
; asm: movd 1032(%rsp), %xmm5
|
||||||
|
regfill v100, ss1 -> %xmm5 ; bin: 66 0f 6e ac 24 00000408
|
||||||
|
|
||||||
; Comparisons.
|
; Comparisons.
|
||||||
;
|
;
|
||||||
; Only `supported_floatccs` are tested here. Others are handled by
|
; Only `supported_floatccs` are tested here. Others are handled by
|
||||||
@@ -412,6 +417,11 @@ ebb0:
|
|||||||
; asm: movq 1032(%rsp), %xmm10
|
; asm: movq 1032(%rsp), %xmm10
|
||||||
[-,%xmm10] v211 = fill v201 ; bin: f3 44 0f 7e 94 24 00000408
|
[-,%xmm10] v211 = fill v201 ; bin: f3 44 0f 7e 94 24 00000408
|
||||||
|
|
||||||
|
; asm: movq %xmm5, 1032(%rsp)
|
||||||
|
regspill v100, %xmm5 -> ss1 ; bin: 66 0f d6 ac 24 00000408
|
||||||
|
; asm: movq 1032(%rsp), %xmm5
|
||||||
|
regfill v100, ss1 -> %xmm5 ; bin: f3 0f 7e ac 24 00000408
|
||||||
|
|
||||||
; Comparisons.
|
; Comparisons.
|
||||||
;
|
;
|
||||||
; Only `supported_floatccs` are tested here. Others are handled by
|
; Only `supported_floatccs` are tested here. Others are handled by
|
||||||
|
|||||||
@@ -459,6 +459,11 @@ ebb0:
|
|||||||
; asm: movq 1032(%rsp), %r10
|
; asm: movq 1032(%rsp), %r10
|
||||||
[-,%r10] v512 = fill v502 ; bin: 4c 8b 94 24 00000408
|
[-,%r10] v512 = fill v502 ; bin: 4c 8b 94 24 00000408
|
||||||
|
|
||||||
|
; asm: movq %rcx, 1032(%rsp)
|
||||||
|
regspill v1, %rcx -> ss1 ; bin: 48 89 8c 24 00000408
|
||||||
|
; asm: movq 1032(%rsp), %rcx
|
||||||
|
regfill v1, ss1 -> %rcx ; bin: 48 8b 8c 24 00000408
|
||||||
|
|
||||||
; asm: testq %rcx, %rcx
|
; asm: testq %rcx, %rcx
|
||||||
; asm: je ebb1
|
; asm: je ebb1
|
||||||
brz v1, ebb1 ; bin: 48 85 c9 74 1b
|
brz v1, ebb1 ; bin: 48 85 c9 74 1b
|
||||||
@@ -850,6 +855,11 @@ ebb0:
|
|||||||
; asm: movl 1032(%rsp), %r10d
|
; asm: movl 1032(%rsp), %r10d
|
||||||
[-,%r10] v512 = fill v502 ; bin: 44 8b 94 24 00000408
|
[-,%r10] v512 = fill v502 ; bin: 44 8b 94 24 00000408
|
||||||
|
|
||||||
|
; asm: movl %ecx, 1032(%rsp)
|
||||||
|
regspill v1, %rcx -> ss1 ; bin: 89 8c 24 00000408
|
||||||
|
; asm: movl 1032(%rsp), %ecx
|
||||||
|
regfill v1, ss1 -> %rcx ; bin: 8b 8c 24 00000408
|
||||||
|
|
||||||
; asm: testl %ecx, %ecx
|
; asm: testl %ecx, %ecx
|
||||||
; asm: je ebb1x
|
; asm: je ebb1x
|
||||||
brz v1, ebb1 ; bin: 85 c9 74 18
|
brz v1, ebb1 ; bin: 85 c9 74 18
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import srcgen
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
from typing import Sequence, List # noqa
|
from typing import Sequence, List # noqa
|
||||||
from cdsl.isa import TargetISA, EncRecipe # noqa
|
from cdsl.isa import TargetISA, EncRecipe, OperandConstraint # noqa
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -49,36 +49,17 @@ def gen_recipe(recipe, fmt):
|
|||||||
fmt.line('..')
|
fmt.line('..')
|
||||||
fmt.outdented_line('} = func.dfg[inst] {')
|
fmt.outdented_line('} = func.dfg[inst] {')
|
||||||
|
|
||||||
|
# Pass recipe arguments in this order: inputs, imm_fields, outputs.
|
||||||
|
args = ''
|
||||||
|
|
||||||
# Normalize to an `args` array.
|
# Normalize to an `args` array.
|
||||||
if want_args and not is_regmove:
|
if want_args and not is_regmove:
|
||||||
if iform.has_value_list:
|
if iform.has_value_list:
|
||||||
fmt.line('let args = args.as_slice(&func.dfg.value_lists);')
|
fmt.line('let args = args.as_slice(&func.dfg.value_lists);')
|
||||||
elif nvops == 1:
|
elif nvops == 1:
|
||||||
fmt.line('let args = [arg];')
|
fmt.line('let args = [arg];')
|
||||||
|
args += unwrap_values(recipe.ins, 'in', 'args', fmt)
|
||||||
|
|
||||||
# Unwrap interesting input arguments.
|
|
||||||
# Don't bother with fixed registers.
|
|
||||||
args = ''
|
|
||||||
for i, arg in enumerate(recipe.ins):
|
|
||||||
if isinstance(arg, RegClass) and not is_regmove:
|
|
||||||
v = 'in_reg{}'.format(i)
|
|
||||||
args += ', ' + v
|
|
||||||
fmt.line(
|
|
||||||
'let {} = divert.reg(args[{}], &func.locations);'
|
|
||||||
.format(v, i))
|
|
||||||
elif isinstance(arg, Stack):
|
|
||||||
v = 'in_stk{}'.format(i)
|
|
||||||
args += ', ' + v
|
|
||||||
with fmt.indented(
|
|
||||||
'let {} = StackRef::masked('.format(v),
|
|
||||||
').unwrap();'):
|
|
||||||
fmt.format(
|
|
||||||
'func.locations[args[{}]].unwrap_stack(),',
|
|
||||||
i)
|
|
||||||
fmt.format('{},', arg.stack_base_mask())
|
|
||||||
fmt.line('&func.stack_slots,')
|
|
||||||
|
|
||||||
# Pass arguments in this order: inputs, imm_fields, outputs.
|
|
||||||
for f in iform.imm_fields:
|
for f in iform.imm_fields:
|
||||||
args += ', ' + f.member
|
args += ', ' + f.member
|
||||||
|
|
||||||
@@ -88,24 +69,7 @@ def gen_recipe(recipe, fmt):
|
|||||||
fmt.line('let results = [func.dfg.first_result(inst)];')
|
fmt.line('let results = [func.dfg.first_result(inst)];')
|
||||||
else:
|
else:
|
||||||
fmt.line('let results = func.dfg.inst_results(inst);')
|
fmt.line('let results = func.dfg.inst_results(inst);')
|
||||||
for i, res in enumerate(recipe.outs):
|
args += unwrap_values(recipe.outs, 'out', 'results', fmt)
|
||||||
if isinstance(res, RegClass):
|
|
||||||
v = 'out_reg{}'.format(i)
|
|
||||||
args += ', ' + v
|
|
||||||
fmt.format(
|
|
||||||
'let {} = func.locations[results[{}]].unwrap_reg();',
|
|
||||||
v, i)
|
|
||||||
elif isinstance(res, Stack):
|
|
||||||
v = 'out_stk{}'.format(i)
|
|
||||||
args += ', ' + v
|
|
||||||
with fmt.indented(
|
|
||||||
'let {} = StackRef::masked('.format(v),
|
|
||||||
').unwrap();'):
|
|
||||||
fmt.format(
|
|
||||||
'func.locations[results[{}]].unwrap_stack(),',
|
|
||||||
i)
|
|
||||||
fmt.format('{},', res.stack_base_mask())
|
|
||||||
fmt.line('&func.stack_slots,')
|
|
||||||
|
|
||||||
# Special handling for regmove instructions. Update the register
|
# Special handling for regmove instructions. Update the register
|
||||||
# diversion tracker.
|
# diversion tracker.
|
||||||
@@ -128,6 +92,36 @@ def gen_recipe(recipe, fmt):
|
|||||||
fmt.line('return;')
|
fmt.line('return;')
|
||||||
|
|
||||||
|
|
||||||
|
def unwrap_values(args, prefix, values, fmt):
|
||||||
|
# type: (Sequence[OperandConstraint], str, str, srcgen.Formatter) -> str # noqa
|
||||||
|
"""
|
||||||
|
Emit code that unwraps values living in registers or stack slots.
|
||||||
|
|
||||||
|
:param args: Input or output constraints.
|
||||||
|
:param prefix: Prefix to be used for the generated local variables.
|
||||||
|
:param values: Name of slice containing the values to be unwrapped.
|
||||||
|
:returns: Comma separated list of the generated variables
|
||||||
|
"""
|
||||||
|
varlist = ''
|
||||||
|
for i, cst in enumerate(args):
|
||||||
|
if isinstance(cst, RegClass):
|
||||||
|
v = '{}_reg{}'.format(prefix, i)
|
||||||
|
varlist += ', ' + v
|
||||||
|
fmt.format(
|
||||||
|
'let {} = divert.reg({}[{}], &func.locations);',
|
||||||
|
v, values, i)
|
||||||
|
elif isinstance(cst, Stack):
|
||||||
|
v = '{}_stk{}'.format(prefix, i)
|
||||||
|
varlist += ', ' + v
|
||||||
|
with fmt.indented(
|
||||||
|
'let {} = StackRef::masked('.format(v),
|
||||||
|
').unwrap();'):
|
||||||
|
fmt.format('divert.stack({}[{}], &func.locations),', values, i)
|
||||||
|
fmt.format('{},', cst.stack_base_mask())
|
||||||
|
fmt.line('&func.stack_slots,')
|
||||||
|
return varlist
|
||||||
|
|
||||||
|
|
||||||
def gen_isa(isa, fmt):
|
def gen_isa(isa, fmt):
|
||||||
# type: (TargetISA, srcgen.Formatter) -> None
|
# type: (TargetISA, srcgen.Formatter) -> None
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ enc_i32_i64_ld_st(base.store, True, r.stDisp8, 0x89)
|
|||||||
enc_i32_i64_ld_st(base.store, True, r.stDisp32, 0x89)
|
enc_i32_i64_ld_st(base.store, True, r.stDisp32, 0x89)
|
||||||
|
|
||||||
enc_i32_i64(base.spill, r.spSib32, 0x89)
|
enc_i32_i64(base.spill, r.spSib32, 0x89)
|
||||||
|
enc_i32_i64(base.regspill, r.rsp32, 0x89)
|
||||||
|
|
||||||
enc_i64(base.istore32.i64.any, r.st, 0x89)
|
enc_i64(base.istore32.i64.any, r.st, 0x89)
|
||||||
enc_i64(base.istore32.i64.any, r.stDisp8, 0x89)
|
enc_i64(base.istore32.i64.any, r.stDisp8, 0x89)
|
||||||
@@ -222,6 +223,7 @@ enc_i32_i64_ld_st(base.load, True, r.ldDisp8, 0x8b)
|
|||||||
enc_i32_i64_ld_st(base.load, True, r.ldDisp32, 0x8b)
|
enc_i32_i64_ld_st(base.load, True, r.ldDisp32, 0x8b)
|
||||||
|
|
||||||
enc_i32_i64(base.fill, r.fiSib32, 0x8b)
|
enc_i32_i64(base.fill, r.fiSib32, 0x8b)
|
||||||
|
enc_i32_i64(base.regfill, r.rfi32, 0x8b)
|
||||||
|
|
||||||
enc_i64(base.uload32.i64, r.ld, 0x8b)
|
enc_i64(base.uload32.i64, r.ld, 0x8b)
|
||||||
enc_i64(base.uload32.i64, r.ldDisp8, 0x8b)
|
enc_i64(base.uload32.i64, r.ldDisp8, 0x8b)
|
||||||
@@ -268,10 +270,14 @@ enc_both(base.store.f64.any, r.fstDisp8, 0x66, 0x0f, 0xd6)
|
|||||||
enc_both(base.store.f64.any, r.fstDisp32, 0x66, 0x0f, 0xd6)
|
enc_both(base.store.f64.any, r.fstDisp32, 0x66, 0x0f, 0xd6)
|
||||||
|
|
||||||
enc_both(base.fill.f32, r.ffiSib32, 0x66, 0x0f, 0x6e)
|
enc_both(base.fill.f32, r.ffiSib32, 0x66, 0x0f, 0x6e)
|
||||||
|
enc_both(base.regfill.f32, r.frfi32, 0x66, 0x0f, 0x6e)
|
||||||
enc_both(base.fill.f64, r.ffiSib32, 0xf3, 0x0f, 0x7e)
|
enc_both(base.fill.f64, r.ffiSib32, 0xf3, 0x0f, 0x7e)
|
||||||
|
enc_both(base.regfill.f64, r.frfi32, 0xf3, 0x0f, 0x7e)
|
||||||
|
|
||||||
enc_both(base.spill.f32, r.fspSib32, 0x66, 0x0f, 0x7e)
|
enc_both(base.spill.f32, r.fspSib32, 0x66, 0x0f, 0x7e)
|
||||||
|
enc_both(base.regspill.f32, r.frsp32, 0x66, 0x0f, 0x7e)
|
||||||
enc_both(base.spill.f64, r.fspSib32, 0x66, 0x0f, 0xd6)
|
enc_both(base.spill.f64, r.fspSib32, 0x66, 0x0f, 0xd6)
|
||||||
|
enc_both(base.regspill.f64, r.frsp32, 0x66, 0x0f, 0xd6)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Function addresses.
|
# Function addresses.
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ from cdsl.registers import RegClass
|
|||||||
from base.formats import Unary, UnaryImm, Binary, BinaryImm, MultiAry
|
from base.formats import Unary, UnaryImm, Binary, BinaryImm, MultiAry
|
||||||
from base.formats import Trap, Call, IndirectCall, Store, Load
|
from base.formats import Trap, Call, IndirectCall, Store, Load
|
||||||
from base.formats import IntCompare, FloatCompare
|
from base.formats import IntCompare, FloatCompare
|
||||||
from base.formats import RegMove, Ternary, Jump, Branch, FuncAddr
|
from base.formats import Ternary, Jump, Branch, 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, StackGPR32, StackFPR32
|
||||||
from .defs import supported_floatccs
|
from .defs import supported_floatccs
|
||||||
|
|
||||||
@@ -570,6 +571,28 @@ fspSib32 = TailRecipe(
|
|||||||
sink.put4(out_stk0.offset as u32);
|
sink.put4(out_stk0.offset as u32);
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
# Regspill using RSP-relative addressing.
|
||||||
|
rsp32 = TailRecipe(
|
||||||
|
'rsp32', RegSpill, size=6, ins=GPR, outs=(),
|
||||||
|
emit='''
|
||||||
|
let dst = StackRef::sp(dst, &func.stack_slots);
|
||||||
|
let base = stk_base(dst.base);
|
||||||
|
PUT_OP(bits, rex2(base, src), sink);
|
||||||
|
modrm_sib_disp32(src, sink);
|
||||||
|
sib_noindex(base, sink);
|
||||||
|
sink.put4(dst.offset as u32);
|
||||||
|
''')
|
||||||
|
frsp32 = TailRecipe(
|
||||||
|
'frsp32', RegSpill, size=6, ins=FPR, outs=(),
|
||||||
|
emit='''
|
||||||
|
let dst = StackRef::sp(dst, &func.stack_slots);
|
||||||
|
let base = stk_base(dst.base);
|
||||||
|
PUT_OP(bits, rex2(base, src), sink);
|
||||||
|
modrm_sib_disp32(src, sink);
|
||||||
|
sib_noindex(base, sink);
|
||||||
|
sink.put4(dst.offset as u32);
|
||||||
|
''')
|
||||||
|
|
||||||
#
|
#
|
||||||
# Load recipes
|
# Load recipes
|
||||||
#
|
#
|
||||||
@@ -656,6 +679,28 @@ ffiSib32 = TailRecipe(
|
|||||||
sink.put4(in_stk0.offset as u32);
|
sink.put4(in_stk0.offset as u32);
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
# Regfill with RSP-relative 32-bit displacement.
|
||||||
|
rfi32 = TailRecipe(
|
||||||
|
'rfi32', RegFill, size=6, ins=StackGPR32, outs=(),
|
||||||
|
emit='''
|
||||||
|
let src = StackRef::sp(src, &func.stack_slots);
|
||||||
|
let base = stk_base(src.base);
|
||||||
|
PUT_OP(bits, rex2(base, dst), sink);
|
||||||
|
modrm_sib_disp32(dst, sink);
|
||||||
|
sib_noindex(base, sink);
|
||||||
|
sink.put4(src.offset as u32);
|
||||||
|
''')
|
||||||
|
frfi32 = TailRecipe(
|
||||||
|
'frfi32', RegFill, size=6, ins=StackFPR32, outs=(),
|
||||||
|
emit='''
|
||||||
|
let src = StackRef::sp(src, &func.stack_slots);
|
||||||
|
let base = stk_base(src.base);
|
||||||
|
PUT_OP(bits, rex2(base, dst), sink);
|
||||||
|
modrm_sib_disp32(dst, sink);
|
||||||
|
sib_noindex(base, sink);
|
||||||
|
sink.put4(src.offset as u32);
|
||||||
|
''')
|
||||||
|
|
||||||
#
|
#
|
||||||
# Call/return
|
# Call/return
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -24,25 +24,28 @@ pub struct StackRef {
|
|||||||
impl StackRef {
|
impl StackRef {
|
||||||
/// Get a reference to the stack slot `ss` using one of the base pointers in `mask`.
|
/// Get a reference to the stack slot `ss` using one of the base pointers in `mask`.
|
||||||
pub fn masked(ss: StackSlot, mask: StackBaseMask, frame: &StackSlots) -> Option<StackRef> {
|
pub fn masked(ss: StackSlot, mask: StackBaseMask, frame: &StackSlots) -> Option<StackRef> {
|
||||||
let size = frame.frame_size.expect(
|
|
||||||
"Stack layout must be computed before referencing stack slots",
|
|
||||||
);
|
|
||||||
// Offsets relative to the caller's stack pointer.
|
|
||||||
let offset = frame[ss].offset;
|
|
||||||
|
|
||||||
// Try an SP-relative reference.
|
// Try an SP-relative reference.
|
||||||
if mask.contains(StackBase::SP) {
|
if mask.contains(StackBase::SP) {
|
||||||
// Offset where SP is pointing. (All ISAs have stacks growing downwards.)
|
return Some(StackRef::sp(ss, frame));
|
||||||
let sp_offset = -(size as StackOffset);
|
|
||||||
return Some(StackRef {
|
|
||||||
base: StackBase::SP,
|
|
||||||
offset: offset - sp_offset,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No reference possible with this mask.
|
// No reference possible with this mask.
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a reference to `ss` using the stack pointer as a base.
|
||||||
|
pub fn sp(ss: StackSlot, frame: &StackSlots) -> StackRef {
|
||||||
|
let size = frame.frame_size.expect(
|
||||||
|
"Stack layout must be computed before referencing stack slots",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Offset where SP is pointing. (All ISAs have stacks growing downwards.)
|
||||||
|
let sp_offset = -(size as StackOffset);
|
||||||
|
return StackRef {
|
||||||
|
base: StackBase::SP,
|
||||||
|
offset: frame[ss].offset - sp_offset,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generic base register for referencing stack slots.
|
/// Generic base register for referencing stack slots.
|
||||||
|
|||||||
Reference in New Issue
Block a user