Skip to content

Commit

Permalink
Merge pull request #12 from lkgv/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
lkgv authored Jun 14, 2023
2 parents 924df96 + 5c56f1e commit d14fb7d
Show file tree
Hide file tree
Showing 58 changed files with 4,652 additions and 582 deletions.
19 changes: 15 additions & 4 deletions pythonstan/analysis/analysis.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
from abc import ABC, abstractmethod
from typing import Dict, Any, Type
from pythonstan.graph.cfg import CFGScope
from typing import Dict, Any, Type, Literal, List

from pythonstan.ir import IRScope


class AnalysisConfig:
name: str
id: str
description: str
type: Literal['dataflow analysis', 'transform']
inter_procedure: bool
prev_analysis: List[str] # previous analysis name
options: Dict[str, Any]

def __init__(self, name, id, description="", options=None):
def __init__(self, name, id, description="", prev_analysis=None, inter_procedure=False, options=None):
self.name = name
self.id = id
self.description = description
self.type = options["type"]
self.inter_procedure = inter_procedure
if options is None:
self.options = {}
else:
self.options = options
if prev_analysis is None:
self.prev_analysis = []
else:
self.prev_analysis = prev_analysis


class Analysis(ABC):
Expand Down Expand Up @@ -45,11 +55,12 @@ def valid_id(self):

class AnalysisDriver(ABC):
config: AnalysisConfig
results: Any

@abstractmethod
def __init__(self, config):
self.config = config

@abstractmethod
def analyze(self, scope: CFGScope):
def analyze(self, scope: IRScope, prev_results: Dict[str, Any]):
pass
31 changes: 23 additions & 8 deletions pythonstan/analysis/dataflow/analysis.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
from abc import ABC, abstractmethod
from typing import TypeVar, Generic
from typing import TypeVar, Generic, Dict, Any

from pythonstan.graph.cfg import CFGScope, Edge, BaseBlock
from pythonstan.graph.cfg import CFGEdge, BaseBlock, ControlFlowGraph
from pythonstan.ir import *
from ..analysis import Analysis, AnalysisConfig

Fact = TypeVar('Fact')


class DataflowAnalysis(Generic[Fact], Analysis):
is_forward: bool
scope: CFGScope

scope: IRScope
inputs: Dict[str, Any]
cfg: ControlFlowGraph
inter_procedure: bool

@abstractmethod
def __init__(self, scope: CFGScope, config: AnalysisConfig):
def __init__(self, scope: IRScope, cfg: ControlFlowGraph, config: AnalysisConfig):
super(Analysis, self.__class__).__init__(config)
self.cfg = cfg
self.scope = scope
self.inputs = {}

@abstractmethod
def new_boundary_fact(self) -> Fact:
Expand All @@ -33,11 +39,20 @@ def transfer_node(self, node: BaseBlock, fact: Fact) -> Fact:
pass

@abstractmethod
def need_transfer_edge(self, edge: Edge) -> bool:
def need_transfer_edge(self, edge: CFGEdge) -> bool:
return False

def transfer_edge(self, edge: Edge, node_fact: Fact) -> Fact:
def transfer_edge(self, edge: CFGEdge, node_fact: Fact) -> Fact:
return node_fact

def get_scope(self) -> CFGScope:
def get_scope(self) -> IRScope:
return self.scope

def get_cfg(self) -> ControlFlowGraph:
return self.cfg

def set_input(self, item: str, value: Any):
self.inputs[item] = value

def get_input(self, item) -> Any:
return self.inputs[item]
16 changes: 11 additions & 5 deletions pythonstan/analysis/dataflow/driver.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import TypeVar, Generic, Dict
from typing import TypeVar, Generic, Dict, Type

from pythonstan.graph.cfg.models import CFGScope
from pythonstan.ir import IRScope
from ..analysis import Analysis, AnalysisDriver, AnalysisConfig
from .analysis import DataflowAnalysis
from .solver import Solver, WorklistSolver
Expand All @@ -9,7 +9,7 @@


class DataflowAnalysisDriver(Generic[Fact], AnalysisDriver):
analysis: DataflowAnalysis
analysis: Type[DataflowAnalysis]
solver: Solver
results: Dict

Expand All @@ -22,8 +22,14 @@ def __init__(self, config: AnalysisConfig):
self.solver = WorklistSolver[Fact]
self.results = {}

def analyze(self, scope: CFGScope):
analyzer = self.analysis(scope, self.config)
def analyze(self, scope: IRScope, prev_results):
from pythonstan.world import World
ir_name = self.config.options.get("ir", "cfg")
cfg = World().scope_manager.get_ir(scope, ir_name)
analyzer = self.analysis(scope, cfg, self.config)
for prev in self.config.prev_analysis:
if prev in prev_results:
analyzer.set_input(prev, prev_results[prev][scope])
facts_in, facts_out = self.solver.solve(analyzer)
self.results = {'in': facts_in,
'out': facts_out}
7 changes: 4 additions & 3 deletions pythonstan/analysis/dataflow/liveness.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from typing import Set

from pythonstan.graph.cfg import BaseBlock
from pythonstan.graph.cfg import BaseBlock, ControlFlowGraph
from . import DataflowAnalysis


class LivenessAnalysis(DataflowAnalysis[Set[str]]):
def __init__(self, scope, config):
def __init__(self, scope, cfg: ControlFlowGraph, config):
self.is_forward = False
super().__init__(scope, config)
self.inter_procedure = False
super().__init__(scope, cfg, config)

def new_boundary_fact(self) -> Set[str]:
return self.new_init_fact()
Expand Down
22 changes: 12 additions & 10 deletions pythonstan/analysis/dataflow/reaching_definition.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
from typing import Set, Dict
from ast import stmt

from pythonstan.graph.cfg import BaseBlock, CFGScope, CFGStmt
from pythonstan.graph.cfg import BaseBlock
from pythonstan.ir import IRScope, IRStatement
from pythonstan.utils.var_collector import VarCollector
from .analysis import DataflowAnalysis


class ReachingDefinitionAnalysis(DataflowAnalysis[Set[CFGStmt]]):
defs: Dict[str, Set[CFGStmt]]
class ReachingDefinitionAnalysis(DataflowAnalysis[Set[IRStatement]]):
defs: Dict[str, Set[IRStatement]]

def __init__(self, scope, config):
def __init__(self, scope, cfg, config):
self.is_forward = True
self.inter_procedure = False
self.defs = self.compute_defs(scope)
super().__init__(scope, config)
super().__init__(scope, cfg, config)

def new_boundary_fact(self) -> Set[CFGStmt]:
def new_boundary_fact(self) -> Set[IRStatement]:
return self.new_init_fact()

def new_init_fact(self) -> Set[CFGStmt]:
def new_init_fact(self) -> Set[IRStatement]:
return {*()}

def meet(self, fact_1: Set[CFGStmt], fact_2: Set[CFGStmt]) -> Set[CFGStmt]:
def meet(self, fact_1: Set[IRStatement], fact_2: Set[IRStatement]) -> Set[IRStatement]:
return fact_1.union(fact_2)

def need_transfer_edge(self, edge):
super().need_transfer_edge(edge)

def compute_defs(self, scope: CFGScope):
def compute_defs(self, scope: IRScope):
defs = {}
for cur_stmt in scope.cfg.stmts:
for var_id in cur_stmt.get_stores():
Expand All @@ -36,7 +38,7 @@ def compute_defs(self, scope: CFGScope):
defs[var_id] = {cur_stmt}
return defs

def transfer_node(self, node: BaseBlock, fact: Set[CFGStmt]) -> Set[CFGStmt]:
def transfer_node(self, node: BaseBlock, fact: Set[IRStatement]) -> Set[IRStatement]:
fact_out = fact.copy()
for cur_stmt in node.stmts:
for var_id in cur_stmt.get_stores():
Expand Down
12 changes: 6 additions & 6 deletions pythonstan/analysis/dataflow/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def init(cls, analysis: DataflowAnalysis[Fact]
def init_forward(cls, analysis: DataflowAnalysis[Fact]
) -> Tuple[Dict[BaseBlock, Fact], Dict[BaseBlock, Fact]]:
in_facts, out_facts = {}, {}
cfg = analysis.get_scope().cfg
cfg = analysis.get_cfg()
for node in cfg.blks:
if node == cfg.entry_blk:
in_facts[node] = analysis.new_boundary_fact()
Expand All @@ -46,7 +46,7 @@ def init_forward(cls, analysis: DataflowAnalysis[Fact]
def init_backward(cls, analysis: DataflowAnalysis[Fact]
) -> Tuple[Dict[BaseBlock, Fact], Dict[BaseBlock, Fact]]:
in_facts, out_facts = {}, {}
cfg = analysis.get_scope().cfg
cfg = analysis.cfg
for node in cfg.blks:
if node == cfg.super_exit_blk:
in_facts[node] = analysis.new_boundary_fact()
Expand Down Expand Up @@ -85,7 +85,7 @@ class WorklistSolver(Generic[Fact], Solver[Fact]):
def init_forward(cls, analysis: DataflowAnalysis[Fact]
) -> Tuple[Dict[BaseBlock, Fact], Dict[BaseBlock, Fact]]:
in_facts, out_facts = {}, {}
cfg = analysis.get_scope().cfg
cfg = analysis.get_cfg()
for node in cfg.blks:
if node == cfg.entry_blk:
in_facts[node] = analysis.new_boundary_fact()
Expand All @@ -108,7 +108,7 @@ def init_forward(cls, analysis: DataflowAnalysis[Fact]
def solve_forward(cls, analysis: DataflowAnalysis[Fact],
in_facts: Dict[BaseBlock, Fact],
out_facts: Dict[BaseBlock, Fact]):
cfg = analysis.get_scope().cfg
cfg = analysis.get_cfg()
work_list = Queue()
for blk in cfg.blks:
if blk != cfg.entry_blk:
Expand All @@ -133,7 +133,7 @@ def solve_forward(cls, analysis: DataflowAnalysis[Fact],
def init_backward(cls, analysis: DataflowAnalysis[Fact]
) -> Tuple[Dict[BaseBlock, Fact], Dict[BaseBlock, Fact]]:
in_facts, out_facts = {}, {}
cfg = analysis.get_scope().cfg
cfg = analysis.get_cfg()
for node in cfg.blks:
if node == cfg.super_exit_blk:
in_facts[node] = analysis.new_boundary_fact()
Expand All @@ -156,7 +156,7 @@ def init_backward(cls, analysis: DataflowAnalysis[Fact]
def solve_backward(cls, analysis: DataflowAnalysis[Fact],
in_facts: Dict[BaseBlock, Fact],
out_facts: Dict[BaseBlock, Fact]):
cfg = analysis.get_scope().cfg
cfg = analysis.get_cfg()
work_list = Queue()
for blk in cfg.blks:
if blk != cfg.super_exit_blk:
Expand Down
4 changes: 2 additions & 2 deletions pythonstan/analysis/defuse.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from ast import stmt
from typing import Set

from pythonstan.graph.cfg import CFGScope
from pythonstan.graph.cfg import IRScope
from .analysis import AnalysisConfig, AnalysisDriver
from .dataflow.driver import DataflowAnalysisDriver

Expand All @@ -20,7 +20,7 @@ def __init__(self, config: AnalysisConfig):
self.rd_analysis = DataflowAnalysisDriver[Set[stmt]](rd_config)
super().__init__(config)

def analyze(self, scope: CFGScope):
def analyze(self, scope: IRScope):
rd_result = self.rd_analysis.analyze(scope)
stores, loads = {}, {}
for cur_stmt in scope.cfg.stmts:
Expand Down
14 changes: 7 additions & 7 deletions pythonstan/analysis/scope/analysis.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from abc import ABC, abstractmethod
from typing import TypeVar, Generic, Optional

from pythonstan.graph.cfg import CFGFunc, CFGClass, CFGModule
from pythonstan.ir import *
from ..analysis import Analysis, AnalysisConfig

Fact = TypeVar('Fact')
Expand All @@ -13,25 +13,25 @@ def __init__(self, config: AnalysisConfig):
super(Analysis, self.__class__).__init__(config)

@abstractmethod
def analyze_function(self, fn: CFGFunc, fact: Optional[Fact]=None) -> Fact:
def analyze_function(self, fn: IRFunc,fact: Optional[Fact] = None) -> Fact:
pass

@abstractmethod
def analyze_class(self, cls: CFGClass, fact: Optional[Fact]=None) -> Fact:
def analyze_class(self, cls: IRClass, fact: Optional[Fact] = None) -> Fact:
pass

@abstractmethod
def analyze_module(self, mod: CFGModule, fact: Optional[Fact]=None) -> Fact:
def analyze_module(self, mod: IRModule, fact: Optional[Fact] = None) -> Fact:
pass

@abstractmethod
def init_function(self, fn: CFGFunc) -> Fact:
def init_function(self, fn: IRFunc) -> Fact:
pass

@abstractmethod
def init_class(self, cls: CFGClass) -> Fact:
def init_class(self, cls: IRClass) -> Fact:
pass

@abstractmethod
def init_module(self, mod: CFGModule) -> Fact:
def init_module(self, mod: IRModule) -> Fact:
pass
14 changes: 7 additions & 7 deletions pythonstan/analysis/scope/closure.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Set

from pythonstan.graph.cfg import CFGClass, CFGFunc, CFGModule
from pythonstan.graph.cfg import IRClass, IRFunc, IRModule
from pythonstan.analysis.dataflow import DataflowAnalysisDriver
from pythonstan.analysis import AnalysisConfig
from pythonstan.utils.var_collector import VarCollector
Expand All @@ -18,7 +18,7 @@ def __init__(self, config: AnalysisConfig):
self.liveness_driver = DataflowAnalysisDriver(liveness_config)
self.in_place = config.options.get('in_place', False)

def analyze_function(self, fn: CFGFunc, fact=None) -> Set[str]:
def analyze_function(self, fn: IRFunc, fact=None) -> Set[str]:
if fact is None:
fact = self.init_function(fn)
self.liveness_driver.analyze(fn)
Expand All @@ -39,7 +39,7 @@ def analyze_function(self, fn: CFGFunc, fact=None) -> Set[str]:
fn.func_def.set_cell_vars(fact)
return fact

def analyze_class(self, cls: CFGClass, fact=None) -> Set[str]:
def analyze_class(self, cls: IRClass, fact=None) -> Set[str]:
if fact is None:
fact = self.init_class(cls)
self.liveness_driver.analyze(cls)
Expand All @@ -54,7 +54,7 @@ def analyze_class(self, cls: CFGClass, fact=None) -> Set[str]:
cls.class_def.set_cell_vars(fact)
return fact

def analyze_module(self, mod: CFGModule, fact=None) -> Set[str]:
def analyze_module(self, mod: IRModule, fact=None) -> Set[str]:
if fact is None:
fact = self.init_module(mod)
self.liveness_driver.analyze(mod)
Expand All @@ -71,11 +71,11 @@ def analyze_module(self, mod: CFGModule, fact=None) -> Set[str]:
fact.update(free_vars)
return fact

def init_function(self, fn: CFGFunc) -> Set[str]:
def init_function(self, fn: IRFunc) -> Set[str]:
return {*()}

def init_class(self, cls: CFGClass) -> Set[str]:
def init_class(self, cls: IRClass) -> Set[str]:
return {*()}

def init_module(self, mod: CFGModule) -> Set[str]:
def init_module(self, mod: IRModule) -> Set[str]:
return {*()}
8 changes: 8 additions & 0 deletions pythonstan/analysis/transform/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from .transform import Transform
from .driver import TransformDriver


from .ssa import *
from .cfg import *
from .block_cfg import *
from .three_address import *
Loading

0 comments on commit d14fb7d

Please sign in to comment.