From 620eb7effef027b643ce9a05e9cd8c765b50dd16 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Mon, 16 Oct 2017 14:06:04 -0700 Subject: [PATCH] Add a "clobbers_flags" flag to encoding recipes. On some ISAs like Intel's, all arithmetic instructions set all or some of the CPU flags, so flag values can't be live across these instructions. On ISAs like ARM's Aarch32, flags are clobbered by compact 16-bit encodings but not necessarily by 32-bit encodings of the same instruction. The "clobbers_flags" bit on the encoding recipe is used to indicate if CPU flag values can be live across an instruction, or conversely whether the encoding can be used where flag values are live. --- lib/cretonne/meta/cdsl/isa.py | 37 ++++++++++++--------- lib/cretonne/meta/gen_encoding.py | 3 ++ lib/cretonne/meta/isa/intel/recipes.py | 46 +++++++++++++++++++++++++- lib/cretonne/src/isa/constraints.rs | 5 +++ 4 files changed, 75 insertions(+), 16 deletions(-) diff --git a/lib/cretonne/meta/cdsl/isa.py b/lib/cretonne/meta/cdsl/isa.py index 2fd8e4c7b5..6d06f8ef0b 100644 --- a/lib/cretonne/meta/cdsl/isa.py +++ b/lib/cretonne/meta/cdsl/isa.py @@ -310,29 +310,35 @@ class EncRecipe(object): branch instructions. It is an `(origin, bits)` tuple describing the exact range that can be encoded in a branch instruction. + For ISAs that use CPU flags in `iflags` and `fflags` value types, the + `clobbers_flags` is used to indicate instruction encodings that clobbers + the CPU flags, so they can't be used where a flag value is live. + :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: ins Tuple of register constraints for value operands. - :param: outs Tuple of register constraints for results. - :param: branch_range `(origin, bits)` range for branches. - :param: instp Instruction predicate. - :param: isap ISA predicate. - :param: emit Rust code for binary emission. + :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. + :param clobbers_flags: This instruction clobbers `iflags` and `fflags`. + :param instp: Instruction predicate. + :param isap: ISA predicate. + :param emit: Rust code for binary emission. """ def __init__( self, - name, # type: str - format, # type: InstructionFormat - size, # type: int - ins, # type: ConstraintSeq - outs, # type: ConstraintSeq - branch_range=None, # type: BranchRange - instp=None, # type: PredNode - isap=None, # type: PredNode - emit=None # type: str + 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 ): # type: (...) -> None self.name = name @@ -340,6 +346,7 @@ class EncRecipe(object): assert size >= 0 self.size = size self.branch_range = branch_range + self.clobbers_flags = clobbers_flags self.instp = instp self.isap = isap self.emit = emit diff --git a/lib/cretonne/meta/gen_encoding.py b/lib/cretonne/meta/gen_encoding.py index 0228c33839..43b00d37f6 100644 --- a/lib/cretonne/meta/gen_encoding.py +++ b/lib/cretonne/meta/gen_encoding.py @@ -766,6 +766,9 @@ def emit_recipe_constraints(isa, fmt): str(any(isinstance(c, Register) for c in r.outs)).lower()) fmt.format('tied_ops: {},', str(bool(tied_i2o)).lower()) + fmt.format( + 'clobbers_flags: {},', + str(bool(r.clobbers_flags)).lower()) def emit_operand_constraints( diff --git a/lib/cretonne/meta/isa/intel/recipes.py b/lib/cretonne/meta/isa/intel/recipes.py index 57506f7833..0aa3f0acd9 100644 --- a/lib/cretonne/meta/isa/intel/recipes.py +++ b/lib/cretonne/meta/isa/intel/recipes.py @@ -147,6 +147,7 @@ class TailRecipe: ins, # type: ConstraintSeq outs, # type: ConstraintSeq branch_range=None, # type: int + clobbers_flags=True, # type: bool instp=None, # type: PredNode isap=None, # type: PredNode when_prefixed=None, # type: TailRecipe @@ -160,6 +161,7 @@ class TailRecipe: self.ins = ins self.outs = outs self.branch_range = branch_range + self.clobbers_flags = clobbers_flags self.instp = instp self.isap = isap self.when_prefixed = when_prefixed @@ -194,6 +196,7 @@ class TailRecipe: ins=self.ins, outs=self.outs, branch_range=branch_range, + clobbers_flags=self.clobbers_flags, instp=self.instp, isap=self.isap, emit=replace_put_op(self.emit, name)) @@ -236,6 +239,7 @@ class TailRecipe: ins=self.ins, outs=self.outs, branch_range=branch_range, + clobbers_flags=self.clobbers_flags, instp=self.instp, isap=self.isap, emit=replace_put_op(self.emit, name)) @@ -302,9 +306,10 @@ fax = TailRecipe( ''') # XX /r, but for a unary operator with separate input/output register, like -# copies. MR form. +# copies. MR form, preserving flags. umr = TailRecipe( 'umr', Unary, size=1, ins=GPR, outs=GPR, + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(out_reg0, in_reg0), sink); modrm_rr(out_reg0, in_reg0, sink); @@ -313,6 +318,7 @@ umr = TailRecipe( # Same as umr, but with FPR -> GPR registers. rfumr = TailRecipe( 'rfumr', Unary, size=1, ins=FPR, outs=GPR, + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(out_reg0, in_reg0), sink); modrm_rr(out_reg0, in_reg0, sink); @@ -339,6 +345,7 @@ urm_abcd = TailRecipe( # XX /r, RM form, FPR -> FPR. furm = TailRecipe( 'furm', Unary, size=1, ins=FPR, outs=FPR, + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg0, out_reg0), sink); modrm_rr(in_reg0, out_reg0, sink); @@ -347,6 +354,7 @@ furm = TailRecipe( # XX /r, RM form, GPR -> FPR. frurm = TailRecipe( 'frurm', Unary, size=1, ins=GPR, outs=FPR, + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg0, out_reg0), sink); modrm_rr(in_reg0, out_reg0, sink); @@ -355,6 +363,7 @@ frurm = TailRecipe( # XX /r, RM form, FPR -> GPR. rfurm = TailRecipe( 'rfurm', Unary, size=1, ins=FPR, outs=GPR, + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg0, out_reg0), sink); modrm_rr(in_reg0, out_reg0, sink); @@ -378,6 +387,7 @@ furmi_rnd = TailRecipe( # XX /r, for regmove instructions. rmov = TailRecipe( 'rmov', RegMove, size=1, ins=GPR, outs=(), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(dst, src), sink); modrm_rr(dst, src, sink); @@ -386,6 +396,7 @@ rmov = TailRecipe( # XX /r, for regmove instructions (FPR version, RM encoded). frmov = TailRecipe( 'frmov', RegMove, size=1, ins=FPR, outs=(), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(src, dst), sink); modrm_rr(src, dst, sink); @@ -489,6 +500,7 @@ fnaddr8 = TailRecipe( st = TailRecipe( 'st', Store, size=1, ins=(GPR, GPR), outs=(), instp=IsEqual(Store.offset, 0), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg1, in_reg0), sink); modrm_rm(in_reg1, in_reg0, sink); @@ -500,6 +512,7 @@ st_abcd = TailRecipe( 'st_abcd', Store, size=1, ins=(ABCD, GPR), outs=(), instp=IsEqual(Store.offset, 0), when_prefixed=st, + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg1, in_reg0), sink); modrm_rm(in_reg1, in_reg0, sink); @@ -509,6 +522,7 @@ st_abcd = TailRecipe( fst = TailRecipe( 'fst', Store, size=1, ins=(FPR, GPR), outs=(), instp=IsEqual(Store.offset, 0), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg1, in_reg0), sink); modrm_rm(in_reg1, in_reg0, sink); @@ -518,6 +532,7 @@ fst = TailRecipe( stDisp8 = TailRecipe( 'stDisp8', Store, size=2, ins=(GPR, GPR), outs=(), instp=IsSignedInt(Store.offset, 8), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg1, in_reg0), sink); modrm_disp8(in_reg1, in_reg0, sink); @@ -528,6 +543,7 @@ stDisp8_abcd = TailRecipe( 'stDisp8_abcd', Store, size=2, ins=(ABCD, GPR), outs=(), instp=IsSignedInt(Store.offset, 8), when_prefixed=stDisp8, + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg1, in_reg0), sink); modrm_disp8(in_reg1, in_reg0, sink); @@ -537,6 +553,7 @@ stDisp8_abcd = TailRecipe( fstDisp8 = TailRecipe( 'fstDisp8', Store, size=2, ins=(FPR, GPR), outs=(), instp=IsSignedInt(Store.offset, 8), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg1, in_reg0), sink); modrm_disp8(in_reg1, in_reg0, sink); @@ -547,6 +564,7 @@ fstDisp8 = TailRecipe( # XX /r register-indirect store with 32-bit offset. stDisp32 = TailRecipe( 'stDisp32', Store, size=5, ins=(GPR, GPR), outs=(), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg1, in_reg0), sink); modrm_disp32(in_reg1, in_reg0, sink); @@ -556,6 +574,7 @@ stDisp32 = TailRecipe( stDisp32_abcd = TailRecipe( 'stDisp32_abcd', Store, size=5, ins=(ABCD, GPR), outs=(), when_prefixed=stDisp32, + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg1, in_reg0), sink); modrm_disp32(in_reg1, in_reg0, sink); @@ -564,6 +583,7 @@ stDisp32_abcd = TailRecipe( ''') fstDisp32 = TailRecipe( 'fstDisp32', Store, size=5, ins=(FPR, GPR), outs=(), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg1, in_reg0), sink); modrm_disp32(in_reg1, in_reg0, sink); @@ -574,6 +594,7 @@ fstDisp32 = TailRecipe( # Unary spill with SIB and 32-bit displacement. spSib32 = TailRecipe( 'spSib32', Unary, size=6, ins=GPR, outs=StackGPR32, + clobbers_flags=False, emit=''' let base = stk_base(out_stk0.base); PUT_OP(bits, rex2(base, in_reg0), sink); @@ -583,6 +604,7 @@ spSib32 = TailRecipe( ''') fspSib32 = TailRecipe( 'fspSib32', Unary, size=6, ins=FPR, outs=StackFPR32, + clobbers_flags=False, emit=''' let base = stk_base(out_stk0.base); PUT_OP(bits, rex2(base, in_reg0), sink); @@ -594,6 +616,7 @@ fspSib32 = TailRecipe( # Regspill using RSP-relative addressing. rsp32 = TailRecipe( 'rsp32', RegSpill, size=6, ins=GPR, outs=(), + clobbers_flags=False, emit=''' let dst = StackRef::sp(dst, &func.stack_slots); let base = stk_base(dst.base); @@ -604,6 +627,7 @@ rsp32 = TailRecipe( ''') frsp32 = TailRecipe( 'frsp32', RegSpill, size=6, ins=FPR, outs=(), + clobbers_flags=False, emit=''' let dst = StackRef::sp(dst, &func.stack_slots); let base = stk_base(dst.base); @@ -621,6 +645,7 @@ frsp32 = TailRecipe( ld = TailRecipe( 'ld', Load, size=1, ins=(GPR), outs=(GPR), instp=IsEqual(Load.offset, 0), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg0, out_reg0), sink); modrm_rm(in_reg0, out_reg0, sink); @@ -630,6 +655,7 @@ ld = TailRecipe( fld = TailRecipe( 'fld', Load, size=1, ins=(GPR), outs=(FPR), instp=IsEqual(Load.offset, 0), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg0, out_reg0), sink); modrm_rm(in_reg0, out_reg0, sink); @@ -639,6 +665,7 @@ fld = TailRecipe( ldDisp8 = TailRecipe( 'ldDisp8', Load, size=2, ins=(GPR), outs=(GPR), instp=IsSignedInt(Load.offset, 8), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg0, out_reg0), sink); modrm_disp8(in_reg0, out_reg0, sink); @@ -650,6 +677,7 @@ ldDisp8 = TailRecipe( fldDisp8 = TailRecipe( 'fldDisp8', Load, size=2, ins=(GPR), outs=(FPR), instp=IsSignedInt(Load.offset, 8), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg0, out_reg0), sink); modrm_disp8(in_reg0, out_reg0, sink); @@ -661,6 +689,7 @@ fldDisp8 = TailRecipe( ldDisp32 = TailRecipe( 'ldDisp32', Load, size=5, ins=(GPR), outs=(GPR), instp=IsSignedInt(Load.offset, 32), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg0, out_reg0), sink); modrm_disp32(in_reg0, out_reg0, sink); @@ -672,6 +701,7 @@ ldDisp32 = TailRecipe( fldDisp32 = TailRecipe( 'fldDisp32', Load, size=5, ins=(GPR), outs=(FPR), instp=IsSignedInt(Load.offset, 32), + clobbers_flags=False, emit=''' PUT_OP(bits, rex2(in_reg0, out_reg0), sink); modrm_disp32(in_reg0, out_reg0, sink); @@ -682,6 +712,7 @@ fldDisp32 = TailRecipe( # Unary fill with SIB and 32-bit displacement. fiSib32 = TailRecipe( 'fiSib32', Unary, size=6, ins=StackGPR32, outs=GPR, + clobbers_flags=False, emit=''' let base = stk_base(in_stk0.base); PUT_OP(bits, rex2(base, out_reg0), sink); @@ -691,6 +722,7 @@ fiSib32 = TailRecipe( ''') ffiSib32 = TailRecipe( 'ffiSib32', Unary, size=6, ins=StackFPR32, outs=FPR, + clobbers_flags=False, emit=''' let base = stk_base(in_stk0.base); PUT_OP(bits, rex2(base, out_reg0), sink); @@ -702,6 +734,7 @@ ffiSib32 = TailRecipe( # Regfill with RSP-relative 32-bit displacement. rfi32 = TailRecipe( 'rfi32', RegFill, size=6, ins=StackGPR32, outs=(), + clobbers_flags=False, emit=''' let src = StackRef::sp(src, &func.stack_slots); let base = stk_base(src.base); @@ -712,6 +745,7 @@ rfi32 = TailRecipe( ''') frfi32 = TailRecipe( 'frfi32', RegFill, size=6, ins=StackFPR32, outs=(), + clobbers_flags=False, emit=''' let src = StackRef::sp(src, &func.stack_slots); let base = stk_base(src.base); @@ -751,6 +785,7 @@ ret = TailRecipe( jmpb = TailRecipe( 'jmpb', Jump, size=1, ins=(), outs=(), branch_range=8, + clobbers_flags=False, emit=''' PUT_OP(bits, BASE_REX, sink); disp1(destination, func, sink); @@ -759,6 +794,7 @@ jmpb = TailRecipe( jmpd = TailRecipe( 'jmpd', Jump, size=4, ins=(), outs=(), branch_range=32, + clobbers_flags=False, emit=''' PUT_OP(bits, BASE_REX, sink); disp4(destination, func, sink); @@ -767,6 +803,7 @@ jmpd = TailRecipe( brib = TailRecipe( 'brib', BranchInt, size=1, ins=FLAG.eflags, outs=(), branch_range=8, + clobbers_flags=False, emit=''' PUT_OP(bits | icc2opc(cond), BASE_REX, sink); disp1(destination, func, sink); @@ -775,6 +812,7 @@ brib = TailRecipe( brid = TailRecipe( 'brid', BranchInt, size=4, ins=FLAG.eflags, outs=(), branch_range=32, + clobbers_flags=False, emit=''' PUT_OP(bits | icc2opc(cond), BASE_REX, sink); disp4(destination, func, sink); @@ -783,6 +821,7 @@ brid = TailRecipe( brfb = TailRecipe( 'brfb', BranchFloat, size=1, ins=FLAG.eflags, outs=(), branch_range=8, + clobbers_flags=False, instp=floatccs(BranchFloat), emit=''' PUT_OP(bits | fcc2opc(cond), BASE_REX, sink); @@ -792,6 +831,7 @@ brfb = TailRecipe( brfd = TailRecipe( 'brfd', BranchFloat, size=4, ins=FLAG.eflags, outs=(), branch_range=32, + clobbers_flags=False, instp=floatccs(BranchFloat), emit=''' PUT_OP(bits | fcc2opc(cond), BASE_REX, sink); @@ -811,6 +851,7 @@ brfd = TailRecipe( seti = TailRecipe( 'seti', IntCond, size=1, ins=FLAG.eflags, outs=GPR, requires_prefix=True, + clobbers_flags=False, emit=''' PUT_OP(bits | icc2opc(cond), rex1(out_reg0), sink); modrm_r_bits(out_reg0, bits, sink); @@ -818,6 +859,7 @@ seti = TailRecipe( seti_abcd = TailRecipe( 'seti_abcd', IntCond, size=1, ins=FLAG.eflags, outs=ABCD, when_prefixed=seti, + clobbers_flags=False, emit=''' PUT_OP(bits | icc2opc(cond), rex1(out_reg0), sink); modrm_r_bits(out_reg0, bits, sink); @@ -826,6 +868,7 @@ seti_abcd = TailRecipe( setf = TailRecipe( 'setf', FloatCond, size=1, ins=FLAG.eflags, outs=GPR, requires_prefix=True, + clobbers_flags=False, emit=''' PUT_OP(bits | fcc2opc(cond), rex1(out_reg0), sink); modrm_r_bits(out_reg0, bits, sink); @@ -833,6 +876,7 @@ setf = TailRecipe( setf_abcd = TailRecipe( 'setf_abcd', FloatCond, size=1, ins=FLAG.eflags, outs=ABCD, when_prefixed=setf, + clobbers_flags=False, emit=''' PUT_OP(bits | fcc2opc(cond), rex1(out_reg0), sink); modrm_r_bits(out_reg0, bits, sink); diff --git a/lib/cretonne/src/isa/constraints.rs b/lib/cretonne/src/isa/constraints.rs index 9efcf7bb4f..aa3268187f 100644 --- a/lib/cretonne/src/isa/constraints.rs +++ b/lib/cretonne/src/isa/constraints.rs @@ -106,6 +106,11 @@ pub struct RecipeConstraints { /// Are there any tied operands? pub tied_ops: bool, + + /// Does this instruction clobber the CPU flags? + /// + /// When true, SSA values of type `iflags` or `fflags` can not be live across the instruction. + pub clobbers_flags: bool, } impl RecipeConstraints {