#ifndef ZEND_SSA_H
#define ZEND_SSA_H
#include "zend_optimizer.h"
#include "zend_cfg.h"
typedef struct _zend_ssa_range {
zend_long min;
zend_long max;
zend_bool underflow;
zend_bool overflow;
} zend_ssa_range;
typedef enum _zend_ssa_negative_lat {
NEG_NONE = 0,
NEG_INIT = 1,
NEG_INVARIANT = 2,
NEG_USE_LT = 3,
NEG_USE_GT = 4,
NEG_UNKNOWN = 5
} zend_ssa_negative_lat;
typedef struct _zend_ssa_range_constraint {
zend_ssa_range range;
int min_var;
int max_var;
int min_ssa_var;
int max_ssa_var;
zend_ssa_negative_lat negative;
} zend_ssa_range_constraint;
typedef struct _zend_ssa_type_constraint {
uint32_t type_mask;
zend_class_entry *ce;
} zend_ssa_type_constraint;
typedef union _zend_ssa_pi_constraint {
zend_ssa_range_constraint range;
zend_ssa_type_constraint type;
} zend_ssa_pi_constraint;
typedef struct _zend_ssa_phi zend_ssa_phi;
struct _zend_ssa_phi {
zend_ssa_phi *next;
int pi;
zend_ssa_pi_constraint constraint;
int var;
int ssa_var;
int block;
int visited : 1;
int has_range_constraint : 1;
zend_ssa_phi **use_chains;
zend_ssa_phi *sym_use_chain;
int *sources;
};
typedef struct _zend_ssa_block {
zend_ssa_phi *phis;
} zend_ssa_block;
typedef struct _zend_ssa_op {
int op1_use;
int op2_use;
int result_use;
int op1_def;
int op2_def;
int result_def;
int op1_use_chain;
int op2_use_chain;
int res_use_chain;
} zend_ssa_op;
typedef struct _zend_ssa_var {
int var;
int scc;
int definition;
zend_ssa_phi *definition_phi;
int use_chain;
zend_ssa_phi *phi_use_chain;
zend_ssa_phi *sym_use_chain;
unsigned int no_val : 1;
unsigned int scc_entry : 1;
} zend_ssa_var;
typedef struct _zend_ssa_var_info {
uint32_t type;
zend_ssa_range range;
zend_class_entry *ce;
unsigned int has_range : 1;
unsigned int is_instanceof : 1;
unsigned int recursive : 1;
unsigned int use_as_double : 1;
} zend_ssa_var_info;
typedef struct _zend_ssa {
zend_cfg cfg;
int rt_constants;
int vars_count;
zend_ssa_block *blocks;
zend_ssa_op *ops;
zend_ssa_var *vars;
int sccs;
zend_ssa_var_info *var_info;
} zend_ssa;
BEGIN_EXTERN_C()
int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, uint32_t *func_flags);
int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa);
int zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var);
END_EXTERN_C()
static zend_always_inline int zend_ssa_next_use(const zend_ssa_op *ssa_op, int var, int use)
{
ssa_op += use;
if (ssa_op->result_use == var) {
return ssa_op->res_use_chain;
}
return (ssa_op->op1_use == var) ? ssa_op->op1_use_chain : ssa_op->op2_use_chain;
}
static zend_always_inline zend_ssa_phi* zend_ssa_next_use_phi(const zend_ssa *ssa, int var, const zend_ssa_phi *p)
{
if (p->pi >= 0) {
return p->use_chains[0];
} else {
int j;
for (j = 0; j < ssa->cfg.blocks[p->block].predecessors_count; j++) {
if (p->sources[j] == var) {
return p->use_chains[j];
}
}
}
return NULL;
}
#endif