Fix #335: Introduce variable size recipes and remove GPR_SAFE reg classes (#552)

* Rename size to base_size and introduce a compute_size function;

* Add infra to inspect in/outs registers when computing the size of an instruction;

* Remove the GPR_SAFE_DEREF and GPR_ZERO_DEREF_SAFE register classes on x86 (fixes #335);
This commit is contained in:
Benjamin Bouvier
2018-10-16 00:43:38 +02:00
committed by Dan Gohman
parent c2069762ef
commit 9d6821d6d9
17 changed files with 498 additions and 240 deletions

View File

@@ -316,7 +316,8 @@ class EncRecipe(object):
:param name: Short mnemonic name for this recipe.
:param format: All encoded instructions must have this
:py:class:`InstructionFormat`.
:param size: Number of bytes in the binary encoded instruction.
:param base_size: Base number of bytes in the binary encoded instruction.
:param compute_size: Function name to use when computing actual size.
:param ins: Tuple of register constraints for value operands.
:param outs: Tuple of register constraints for results.
:param branch_range: `(origin, bits)` range for branches.
@@ -328,22 +329,25 @@ class EncRecipe(object):
def __init__(
self,
name, # type: str
format, # type: InstructionFormat
size, # type: int
ins, # type: ConstraintSeq
outs, # type: ConstraintSeq
branch_range=None, # type: BranchRange
clobbers_flags=True, # type: bool
instp=None, # type: PredNode
isap=None, # type: PredNode
emit=None # type: str
name, # type: str
format, # type: InstructionFormat
base_size, # type: int
ins, # type: ConstraintSeq
outs, # type: ConstraintSeq
compute_size=None, # type: str
branch_range=None, # type: BranchRange
clobbers_flags=True, # type: bool
instp=None, # type: PredNode
isap=None, # type: PredNode
emit=None # type: str
):
# type: (...) -> None
self.name = name
self.format = format
assert size >= 0
self.size = size
assert base_size >= 0
self.base_size = base_size
self.compute_size = compute_size if compute_size is not None \
else 'base_size'
self.branch_range = branch_range
self.clobbers_flags = clobbers_flags
self.instp = instp

View File

@@ -832,7 +832,8 @@ def emit_recipe_sizing(isa, fmt):
for r in isa.all_recipes:
fmt.comment('Code size information for recipe {}:'.format(r.name))
with fmt.indented('RecipeSizing {', '},'):
fmt.format('bytes: {},', r.size)
fmt.format('base_size: {},', r.base_size)
fmt.format('compute_size: {},', r.compute_size)
if r.branch_range:
fmt.format(
'branch_range: '

View File

@@ -93,33 +93,33 @@ def LUI():
# R-type 32-bit instructions: These are mostly binary arithmetic instructions.
# The encbits are `opcode[6:2] | (funct3 << 5) | (funct7 << 8)
R = EncRecipe(
'R', Binary, size=4, ins=(GPR, GPR), outs=GPR,
'R', Binary, base_size=4, ins=(GPR, GPR), outs=GPR,
emit='put_r(bits, in_reg0, in_reg1, out_reg0, sink);')
# R-type with an immediate shift amount instead of rs2.
Rshamt = EncRecipe(
'Rshamt', BinaryImm, size=4, ins=GPR, outs=GPR,
'Rshamt', BinaryImm, base_size=4, ins=GPR, outs=GPR,
emit='put_rshamt(bits, in_reg0, imm.into(), out_reg0, sink);')
# R-type encoding of an integer comparison.
Ricmp = EncRecipe(
'Ricmp', IntCompare, size=4, ins=(GPR, GPR), outs=GPR,
'Ricmp', IntCompare, base_size=4, ins=(GPR, GPR), outs=GPR,
emit='put_r(bits, in_reg0, in_reg1, out_reg0, sink);')
Ii = EncRecipe(
'Ii', BinaryImm, size=4, ins=GPR, outs=GPR,
'Ii', BinaryImm, base_size=4, ins=GPR, outs=GPR,
instp=IsSignedInt(BinaryImm.imm, 12),
emit='put_i(bits, in_reg0, imm.into(), out_reg0, sink);')
# I-type instruction with a hardcoded %x0 rs1.
Iz = EncRecipe(
'Iz', UnaryImm, size=4, ins=(), outs=GPR,
'Iz', UnaryImm, base_size=4, ins=(), outs=GPR,
instp=IsSignedInt(UnaryImm.imm, 12),
emit='put_i(bits, 0, imm.into(), out_reg0, sink);')
# I-type encoding of an integer comparison.
Iicmp = EncRecipe(
'Iicmp', IntCompareImm, size=4, ins=GPR, outs=GPR,
'Iicmp', IntCompareImm, base_size=4, ins=GPR, outs=GPR,
instp=IsSignedInt(IntCompareImm.imm, 12),
emit='put_i(bits, in_reg0, imm.into(), out_reg0, sink);')
@@ -127,7 +127,7 @@ Iicmp = EncRecipe(
# immediate offset.
# The variable return values are not encoded.
Iret = EncRecipe(
'Iret', MultiAry, size=4, ins=(), outs=(),
'Iret', MultiAry, base_size=4, ins=(), outs=(),
emit='''
// Return instructions are always a jalr to %x1.
// The return address is provided as a special-purpose link argument.
@@ -142,7 +142,7 @@ Iret = EncRecipe(
# I-type encoding for `jalr` as a call_indirect.
Icall = EncRecipe(
'Icall', CallIndirect, size=4, ins=GPR, outs=(),
'Icall', CallIndirect, base_size=4, ins=GPR, outs=(),
emit='''
// call_indirect instructions are jalr with rd=%x1.
put_i(
@@ -157,23 +157,23 @@ Icall = EncRecipe(
# Copy of a GPR is implemented as addi x, 0.
Icopy = EncRecipe(
'Icopy', Unary, size=4, ins=GPR, outs=GPR,
'Icopy', Unary, base_size=4, ins=GPR, outs=GPR,
emit='put_i(bits, in_reg0, 0, out_reg0, sink);')
# Same for a GPR regmove.
Irmov = EncRecipe(
'Irmov', RegMove, size=4, ins=GPR, outs=(),
'Irmov', RegMove, base_size=4, ins=GPR, outs=(),
emit='put_i(bits, src, 0, dst, sink);')
# U-type instructions have a 20-bit immediate that targets bits 12-31.
U = EncRecipe(
'U', UnaryImm, size=4, ins=(), outs=GPR,
'U', UnaryImm, base_size=4, ins=(), outs=GPR,
instp=IsSignedInt(UnaryImm.imm, 32, 12),
emit='put_u(bits, imm.into(), out_reg0, sink);')
# UJ-type unconditional branch instructions.
UJ = EncRecipe(
'UJ', Jump, size=4, ins=(), outs=(), branch_range=(0, 21),
'UJ', Jump, base_size=4, ins=(), outs=(), branch_range=(0, 21),
emit='''
let dest = i64::from(func.offsets[destination]);
let disp = dest - i64::from(sink.offset());
@@ -181,7 +181,7 @@ UJ = EncRecipe(
''')
UJcall = EncRecipe(
'UJcall', Call, size=4, ins=(), outs=(),
'UJcall', Call, base_size=4, ins=(), outs=(),
emit='''
sink.reloc_external(Reloc::RiscvCall,
&func.dfg.ext_funcs[func_ref].name,
@@ -192,7 +192,7 @@ UJcall = EncRecipe(
# SB-type branch instructions.
SB = EncRecipe(
'SB', BranchIcmp, size=4,
'SB', BranchIcmp, base_size=4,
ins=(GPR, GPR), outs=(),
branch_range=(0, 13),
emit='''
@@ -203,7 +203,7 @@ SB = EncRecipe(
# SB-type branch instruction with rs2 fixed to zero.
SBzero = EncRecipe(
'SBzero', Branch, size=4,
'SBzero', Branch, base_size=4,
ins=(GPR), outs=(),
branch_range=(0, 13),
emit='''
@@ -214,12 +214,12 @@ SBzero = EncRecipe(
# Spill of a GPR.
GPsp = EncRecipe(
'GPsp', Unary, size=4,
'GPsp', Unary, base_size=4,
ins=GPR, outs=Stack(GPR),
emit='unimplemented!();')
# Fill of a GPR.
GPfi = EncRecipe(
'GPfi', Unary, size=4,
'GPfi', Unary, base_size=4,
ins=Stack(GPR), outs=GPR,
emit='unimplemented!();')

File diff suppressed because it is too large Load Diff

View File

@@ -46,14 +46,7 @@ FlagRegs = RegBank(
names=['rflags'])
GPR = RegClass(IntRegs)
# Certain types of deref encodings cannot be used with all registers.
# R13/RBP cannot be used with zero-offset load or store instructions.
# R12 cannot be used with a non-SIB-byte encoding of all derefs.
GPR_DEREF_SAFE = GPR.without(GPR.rsp, GPR.r12)
GPR_ZERO_DEREF_SAFE = GPR_DEREF_SAFE.without(GPR.rbp, GPR.r13)
GPR8 = GPR[0:8]
GPR8_DEREF_SAFE = GPR8.without(GPR.rsp)
GPR8_ZERO_DEREF_SAFE = GPR8_DEREF_SAFE.without(GPR.rbp)
ABCD = GPR[0:4]
FPR = RegClass(FloatRegs)
FPR8 = FPR[0:8]