Skip to content

Commit

Permalink
fixed some bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
lkgv committed Jun 14, 2023
1 parent e9a16e5 commit 5c56f1e
Show file tree
Hide file tree
Showing 61 changed files with 248 additions and 4,406 deletions.
5 changes: 3 additions & 2 deletions pythonstan/analysis/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class AnalysisConfig:
name: str
id: str
description: str
type: Literal['dataflow_analysis', 'transform']
type: Literal['dataflow analysis', 'transform']
inter_procedure: bool
prev_analysis: List[str] # previous analysis name
options: Dict[str, Any]
Expand Down Expand Up @@ -55,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: IRScope):
def analyze(self, scope: IRScope, prev_results: Dict[str, Any]):
pass
26 changes: 20 additions & 6 deletions pythonstan/analysis/dataflow/analysis.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from abc import ABC, abstractmethod
from typing import TypeVar, Generic
from typing import TypeVar, Generic, Dict, Any

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

Fact = TypeVar('Fact')
Expand All @@ -10,12 +11,16 @@
class DataflowAnalysis(Generic[Fact], Analysis):
is_forward: bool
scope: IRScope
inputs: Dict[str, Any]
cfg: ControlFlowGraph
inter_procedure: bool

@abstractmethod
def __init__(self, scope: IRScope, 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 @@ -34,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) -> 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]
12 changes: 9 additions & 3 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, 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 @@ -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}
6 changes: 3 additions & 3 deletions pythonstan/analysis/dataflow/liveness.py
Original file line number Diff line number Diff line change
@@ -1,14 +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
self.inter_procedure = False
super().__init__(scope, config)
super().__init__(scope, cfg, config)

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

from pythonstan.graph.cfg import BaseBlock, IRScope, IRRStatement
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[IRRStatement]]):
defs: Dict[str, Set[IRRStatement]]
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[IRRStatement]:
def new_boundary_fact(self) -> Set[IRStatement]:
return self.new_init_fact()

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

def meet(self, fact_1: Set[IRRStatement], fact_2: Set[IRRStatement]) -> Set[IRRStatement]:
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):
Expand All @@ -37,7 +38,7 @@ def compute_defs(self, scope: IRScope):
defs[var_id] = {cur_stmt}
return defs

def transfer_node(self, node: BaseBlock, fact: Set[IRRStatement]) -> Set[IRRStatement]:
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
8 changes: 4 additions & 4 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 IRFunc, IRClass, IRModule
from pythonstan.ir import *
from ..analysis import Analysis, AnalysisConfig

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

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

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

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

@abstractmethod
Expand Down
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 *
19 changes: 12 additions & 7 deletions pythonstan/analysis/transform/block_cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from ..analysis import AnalysisConfig
from .transform import Transform
from pythonstan.graph.cfg import *
from pythonstan.world import World

from pythonstan.ir import *


Expand All @@ -19,16 +19,17 @@ def __init__(self, config: AnalysisConfig):
self.transformer = BlockCFGBuilder()

def transform(self, module: IRModule):
from pythonstan.world import World
three_address_form = World().scope_manager.get_ir(module, "three address form")
imports = self.transformer.build_module(self.module, three_address_form)
imports = self.transformer.build_module(module, three_address_form.body)
self.results = imports


class LabelGenerator:
next_idx: int

def __init__(self):
next_idx = 0
self.next_idx = 0

def gen(self) -> Label:
label = Label(self.next_idx)
Expand Down Expand Up @@ -61,6 +62,7 @@ def new_blk(self) -> BaseBlock:
return blk

def build_module(self, module: IRModule, stmts: List[Statement]) -> List[IRImport]:
from pythonstan.world import World
builder = BlockCFGBuilder(scope=module)
new_blk = builder.new_blk()
edge = NormalEdge(builder.cfg.entry_blk, new_blk)
Expand All @@ -72,6 +74,7 @@ def build_module(self, module: IRModule, stmts: List[Statement]) -> List[IRImpor
return [ir_stmt for _, ir_stmt in mod_info['import']]

def build_func(self, func_def) -> Tuple[IRFunc, List[Tuple[BaseBlock, IRImport]]]:
from pythonstan.world import World
qualname = f"{self.scope.get_qualname()}.{func_def.name}"
func = IRFunc(qualname, func_def)
builder = BlockCFGBuilder(scope=func)
Expand All @@ -92,6 +95,7 @@ def build_func(self, func_def) -> Tuple[IRFunc, List[Tuple[BaseBlock, IRImport]]
return func, func_info['import']

def build_class(self, cls_def: ast.ClassDef) -> Tuple[IRClass, List[Tuple[BaseBlock, IRImport]]]:
from pythonstan.world import World
qualname = f"{self.scope.get_qualname()}.{cls_def.name}"
cls = IRClass(qualname, cls_def)
builder = BlockCFGBuilder(scope=cls)
Expand Down Expand Up @@ -215,18 +219,19 @@ def extend_info(info, exclude=None, include=None):
cur_blk = next_blk

elif isinstance(stmt, ast.If):
if_false_jump = JumpIfFalse(test=stmt.test)
test_expr = stmt.test
if_false_jump = JumpIfFalse(test=test_expr)
cfg.add_stmt(cur_blk, if_false_jump)
then_blk = gen_next_blk(i, cur_blk,
lambda u, v: IfEdge(u, v, True),
lambda u, v: IfEdge(u, v, test_expr, True),
True)
then_info = self._build(stmt.body, cfg, then_blk)
extend_info(then_info)
next_blk = self.new_blk()
cfg.add_edge(NormalEdge(then_info['last_block'], next_blk))
if len(stmt.orelse) > 0:
else_blk = gen_next_blk(i, cur_blk,
lambda u, v: IfEdge(u, v, False),
lambda u, v: IfEdge(u, v, test_expr, False),
True)
else_info = self._build(stmt.orelse, cfg, else_blk)
extend_info(else_info)
Expand All @@ -238,7 +243,7 @@ def extend_info(info, exclude=None, include=None):
else_label = self.label_gen.gen()
cfg.add_label(else_label, else_blk)
else:
cfg.add_edge(IfEdge(cur_blk, next_blk, False))
cfg.add_edge(IfEdge(cur_blk, next_blk, test_expr, False))
else_label = self.label_gen.gen()
cfg.add_label(else_label, next_blk)
if_false_jump.set_label(else_label)
Expand Down
6 changes: 4 additions & 2 deletions pythonstan/analysis/transform/cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from ..analysis import AnalysisConfig
from .transform import Transform
from pythonstan.graph.cfg import *
from pythonstan.world import World

from pythonstan.ir import *

__all__ = ["CFG"]
Expand All @@ -18,8 +18,9 @@ def __init__(self, config: AnalysisConfig):
self.transformer = CFGTransformer()

def transform(self, module: IRModule):
from pythonstan.world import World
block_cfg = World().scope_manager.get_ir(module, "block cfg")
self.transformer.trans(self.module, block_cfg)
self.transformer.trans(module, block_cfg)
self.results = None


Expand All @@ -32,6 +33,7 @@ class CFGTransformer:
next_idx: int

def trans(self, scope: IRScope, block_cfg: ControlFlowGraph):
from pythonstan.world import World
self.scope = scope
self.cfg = ControlFlowGraph()
entry = self.cfg.get_entry()
Expand Down
18 changes: 10 additions & 8 deletions pythonstan/analysis/transform/driver.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import Dict, Type, Any

from pythonstan.ir.ir_module import IRModule
from pythonstan.world import World
from pythonstan.ir import IRScope
from ..analysis import Analysis, AnalysisConfig, AnalysisDriver
from .transform import Transform

Expand All @@ -13,12 +12,15 @@ class TransformDriver(AnalysisDriver):
def __init__(self, config):
self.config = config
self.transform = Transform.get_analysis(config.id)
self.results = {}

def analyze(self, module: IRModule) -> Any:
def analyze(self, scope: IRScope, prev_results):
analyzer = self.transform(self.config)
for prev in self.config.prev_analysis:
prev_results = World().analysis_manager.get_results(prev)
if prev_results is not None:
analyzer.set_input(prev, prev_results[module.get_name()])
analyzer.transform(module)
return analyzer.results
if prev in prev_results:
analyzer.set_input(prev, prev_results[prev][scope])
analyzer.transform(scope)
if hasattr(analyzer, "results"):
self.results[scope] = analyzer.results
else:
self.results[scope] = None
Loading

0 comments on commit 5c56f1e

Please sign in to comment.