Skip to content

gh-106149: move CFG and basicblock definitions into flowgraph.c, use them as opaque types in compile.c #107639

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 10, 2023
5 changes: 5 additions & 0 deletions Include/internal/pycore_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ typedef struct {
int s_next_free_label; /* next free label id */
} _PyCompile_InstructionSequence;

int _PyCompile_InstructionSequence_UseLabel(_PyCompile_InstructionSequence *seq, int lbl);
int _PyCompile_InstructionSequence_Addop(_PyCompile_InstructionSequence *seq,
int opcode, int oparg,
_PyCompilerSrcLocation loc);

typedef struct {
PyObject *u_name;
PyObject *u_qualname; /* dot-separated qualified name (lazy) */
Expand Down
86 changes: 12 additions & 74 deletions Include/internal/pycore_flowgraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,88 +11,26 @@ extern "C" {
#include "pycore_opcode_utils.h"
#include "pycore_compile.h"


typedef struct {
int i_opcode;
int i_oparg;
_PyCompilerSrcLocation i_loc;
struct _PyCfgBasicblock_ *i_target; /* target block (if jump instruction) */
struct _PyCfgBasicblock_ *i_except; /* target block when exception is raised */
} _PyCfgInstruction;

typedef struct {
int id;
} _PyCfgJumpTargetLabel;

struct _PyCfgBuilder;

typedef struct {
struct _PyCfgBasicblock_ *handlers[CO_MAXBLOCKS+1];
int depth;
} _PyCfgExceptStack;

typedef struct _PyCfgBasicblock_ {
/* Each basicblock in a compilation unit is linked via b_list in the
reverse order that the block are allocated. b_list points to the next
block in this list, not to be confused with b_next, which is next by
control flow. */
struct _PyCfgBasicblock_ *b_list;
/* The label of this block if it is a jump target, -1 otherwise */
_PyCfgJumpTargetLabel b_label;
/* Exception stack at start of block, used by assembler to create the exception handling table */
_PyCfgExceptStack *b_exceptstack;
/* pointer to an array of instructions, initially NULL */
_PyCfgInstruction *b_instr;
/* If b_next is non-NULL, it is a pointer to the next
block reached by normal control flow. */
struct _PyCfgBasicblock_ *b_next;
/* number of instructions used */
int b_iused;
/* length of instruction array (b_instr) */
int b_ialloc;
/* Used by add_checks_for_loads_of_unknown_variables */
uint64_t b_unsafe_locals_mask;
/* Number of predecessors that a block has. */
int b_predecessors;
/* depth of stack upon entry of block, computed by stackdepth() */
int b_startdepth;
/* Basic block is an exception handler that preserves lasti */
unsigned b_preserve_lasti : 1;
/* Used by compiler passes to mark whether they have visited a basic block. */
unsigned b_visited : 1;
/* b_except_handler is used by the cold-detection algorithm to mark exception targets */
unsigned b_except_handler : 1;
/* b_cold is true if this block is not perf critical (like an exception handler) */
unsigned b_cold : 1;
/* b_warm is used by the cold-detection algorithm to mark blocks which are definitely not cold */
unsigned b_warm : 1;
} _PyCfgBasicblock;
int _PyCfgBuilder_UseLabel(struct _PyCfgBuilder *g, _PyCfgJumpTargetLabel lbl);
int _PyCfgBuilder_Addop(struct _PyCfgBuilder *g, int opcode, int oparg, _PyCompilerSrcLocation loc);

int _PyBasicblock_InsertInstruction(_PyCfgBasicblock *block, int pos, _PyCfgInstruction *instr);
struct _PyCfgBuilder* _PyCfgBuilder_New(void);
void _PyCfgBuilder_Free(struct _PyCfgBuilder *g);
int _PyCfgBuilder_CheckSize(struct _PyCfgBuilder* g);

typedef struct cfg_builder_ {
/* The entryblock, at which control flow begins. All blocks of the
CFG are reachable through the b_next links */
_PyCfgBasicblock *g_entryblock;
/* Pointer to the most recently allocated block. By following
b_list links, you can reach all allocated blocks. */
_PyCfgBasicblock *g_block_list;
/* pointer to the block currently being constructed */
_PyCfgBasicblock *g_curblock;
/* label for the next instruction to be placed */
_PyCfgJumpTargetLabel g_current_label;
} _PyCfgBuilder;

int _PyCfgBuilder_UseLabel(_PyCfgBuilder *g, _PyCfgJumpTargetLabel lbl);
int _PyCfgBuilder_Addop(_PyCfgBuilder *g, int opcode, int oparg, _PyCompilerSrcLocation loc);

int _PyCfgBuilder_Init(_PyCfgBuilder *g);
void _PyCfgBuilder_Fini(_PyCfgBuilder *g);

int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache,
int _PyCfg_OptimizeCodeUnit(struct _PyCfgBuilder *g, PyObject *consts, PyObject *const_cache,
int nlocals, int nparams, int firstlineno);
int _PyCfg_Stackdepth(_PyCfgBuilder *g);
void _PyCfg_ConvertPseudoOps(_PyCfgBasicblock *entryblock);
int _PyCfg_ResolveJumps(_PyCfgBuilder *g);

int _PyCfg_ToInstructionSequence(struct _PyCfgBuilder *g, _PyCompile_InstructionSequence *seq);
int _PyCfg_OptimizedCfgToInstructionSequence(struct _PyCfgBuilder *g, _PyCompile_CodeUnitMetadata *umd,
int code_flags, int *stackdepth, int *nlocalsplus,
_PyCompile_InstructionSequence *seq);

PyCodeObject *
_PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *u, PyObject *const_cache,
Expand Down
Loading