gh-106149: move unconditional jump direction resolution from optimizer to assembler (#106291)

This commit is contained in:
Irit Katriel 2023-07-01 11:28:07 +01:00 committed by GitHub
parent d3abc9b516
commit 200f255411
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 20 deletions

View file

@ -674,11 +674,45 @@ resolve_jump_offsets(instr_sequence *instrs)
return SUCCESS; return SUCCESS;
} }
static int
resolve_unconditional_jumps(instr_sequence *instrs)
{
/* Resolve directions of unconditional jumps */
for (int i = 0; i < instrs->s_used; i++) {
instruction *instr = &instrs->s_instrs[i];
bool is_forward = (instr->i_oparg > i);
switch(instr->i_opcode) {
case JUMP:
assert(SAME_OPCODE_METADATA(JUMP, JUMP_FORWARD));
assert(SAME_OPCODE_METADATA(JUMP, JUMP_BACKWARD));
instr->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD;
break;
case JUMP_NO_INTERRUPT:
assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_FORWARD));
assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_BACKWARD_NO_INTERRUPT));
instr->i_opcode = is_forward ?
JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT;
break;
default:
if (OPCODE_HAS_JUMP(instr->i_opcode) &&
IS_PSEUDO_INSTR(instr->i_opcode)) {
Py_UNREACHABLE();
}
}
}
return SUCCESS;
}
PyCodeObject * PyCodeObject *
_PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *umd, PyObject *const_cache, _PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *umd, PyObject *const_cache,
PyObject *consts, int maxdepth, instr_sequence *instrs, PyObject *consts, int maxdepth, instr_sequence *instrs,
int nlocalsplus, int code_flags, PyObject *filename) int nlocalsplus, int code_flags, PyObject *filename)
{ {
if (resolve_unconditional_jumps(instrs) < 0) {
return NULL;
}
if (resolve_jump_offsets(instrs) < 0) { if (resolve_jump_offsets(instrs) < 0) {
return NULL; return NULL;
} }

View file

@ -393,24 +393,17 @@ no_redundant_jumps(cfg_builder *g) {
static int static int
normalize_jumps_in_block(cfg_builder *g, basicblock *b) { normalize_jumps_in_block(cfg_builder *g, basicblock *b) {
cfg_instr *last = _PyCfg_BasicblockLastInstr(b); cfg_instr *last = _PyCfg_BasicblockLastInstr(b);
if (last == NULL || !is_jump(last)) { if (last == NULL || !is_jump(last) ||
IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) {
return SUCCESS; return SUCCESS;
} }
assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); assert(!IS_ASSEMBLER_OPCODE(last->i_opcode));
bool is_forward = last->i_target->b_visited == 0; bool is_forward = last->i_target->b_visited == 0;
switch(last->i_opcode) { if (is_forward) {
case JUMP:
assert(SAME_OPCODE_METADATA(JUMP, JUMP_FORWARD));
assert(SAME_OPCODE_METADATA(JUMP, JUMP_BACKWARD));
last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD;
return SUCCESS;
case JUMP_NO_INTERRUPT:
assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_FORWARD));
assert(SAME_OPCODE_METADATA(JUMP_NO_INTERRUPT, JUMP_BACKWARD_NO_INTERRUPT));
last->i_opcode = is_forward ?
JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT;
return SUCCESS; return SUCCESS;
} }
int reversed_opcode = 0; int reversed_opcode = 0;
switch(last->i_opcode) { switch(last->i_opcode) {
case POP_JUMP_IF_NOT_NONE: case POP_JUMP_IF_NOT_NONE:
@ -426,9 +419,6 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) {
reversed_opcode = POP_JUMP_IF_FALSE; reversed_opcode = POP_JUMP_IF_FALSE;
break; break;
} }
if (is_forward) {
return SUCCESS;
}
/* transform 'conditional jump T' to /* transform 'conditional jump T' to
* 'reversed_jump b_next' followed by 'jump_backwards T' * 'reversed_jump b_next' followed by 'jump_backwards T'
*/ */

View file

@ -4,7 +4,7 @@
// Do not edit! // Do not edit!
#define IS_PSEUDO_INSTR(OP) \ #define IS_PSEUDO_INSTR(OP) ( \
((OP) == LOAD_CLOSURE) || \ ((OP) == LOAD_CLOSURE) || \
((OP) == STORE_FAST_MAYBE_NULL) || \ ((OP) == STORE_FAST_MAYBE_NULL) || \
((OP) == LOAD_SUPER_METHOD) || \ ((OP) == LOAD_SUPER_METHOD) || \
@ -17,7 +17,7 @@
((OP) == SETUP_CLEANUP) || \ ((OP) == SETUP_CLEANUP) || \
((OP) == SETUP_WITH) || \ ((OP) == SETUP_WITH) || \
((OP) == POP_BLOCK) || \ ((OP) == POP_BLOCK) || \
0 0)
#define EXIT_TRACE 300 #define EXIT_TRACE 300
#define SET_IP 301 #define SET_IP 301

View file

@ -1310,10 +1310,10 @@ class Analyzer:
def write_pseudo_instrs(self) -> None: def write_pseudo_instrs(self) -> None:
"""Write the IS_PSEUDO_INSTR macro""" """Write the IS_PSEUDO_INSTR macro"""
self.out.emit("\n\n#define IS_PSEUDO_INSTR(OP) \\") self.out.emit("\n\n#define IS_PSEUDO_INSTR(OP) ( \\")
for op in self.pseudos: for op in self.pseudos:
self.out.emit(f" ((OP) == {op}) || \\") self.out.emit(f" ((OP) == {op}) || \\")
self.out.emit(f" 0") self.out.emit(f" 0)")
def write_uop_items(self, make_text: typing.Callable[[str, int], str]) -> None: def write_uop_items(self, make_text: typing.Callable[[str, int], str]) -> None:
"""Write '#define XXX NNN' for each uop""" """Write '#define XXX NNN' for each uop"""