forked from M-Labs/artiq
transforms.cfg_simplifier: remove.
Specifically, the following idiom broke our CFGSimplifier: b1: branch_if %cond, %b2, %b3 b2: branch %b3 b3: %v = phi [ %b2 => 0, %b3 => 1 ] This is very annoying to properly handle in general case, and also this (specifically %b2) is exactly what broke LocalAccessValidator in the first place. So, remove CFGSimplifier altogether. Instead, teach LocalAccessValidator how to look through predecessors in order to get a location.
This commit is contained in:
parent
17802d3cff
commit
9ed6b54249
|
@ -55,7 +55,6 @@ class Module:
|
||||||
artiq_ir_generator = transforms.ARTIQIRGenerator(engine=self.engine,
|
artiq_ir_generator = transforms.ARTIQIRGenerator(engine=self.engine,
|
||||||
module_name=src.name,
|
module_name=src.name,
|
||||||
ref_period=ref_period)
|
ref_period=ref_period)
|
||||||
cfg_simplifier = transforms.CFGSimplifier(engine=self.engine)
|
|
||||||
dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine)
|
dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine)
|
||||||
local_access_validator = validators.LocalAccessValidator(engine=self.engine)
|
local_access_validator = validators.LocalAccessValidator(engine=self.engine)
|
||||||
devirtualization = analyses.Devirtualization()
|
devirtualization = analyses.Devirtualization()
|
||||||
|
@ -71,7 +70,6 @@ class Module:
|
||||||
devirtualization.visit(src.typedtree)
|
devirtualization.visit(src.typedtree)
|
||||||
self.artiq_ir = artiq_ir_generator.visit(src.typedtree)
|
self.artiq_ir = artiq_ir_generator.visit(src.typedtree)
|
||||||
artiq_ir_generator.annotate_calls(devirtualization)
|
artiq_ir_generator.annotate_calls(devirtualization)
|
||||||
cfg_simplifier.process(self.artiq_ir)
|
|
||||||
dead_code_eliminator.process(self.artiq_ir)
|
dead_code_eliminator.process(self.artiq_ir)
|
||||||
interleaver.process(self.artiq_ir)
|
interleaver.process(self.artiq_ir)
|
||||||
local_access_validator.process(self.artiq_ir)
|
local_access_validator.process(self.artiq_ir)
|
||||||
|
|
|
@ -4,6 +4,5 @@ from .int_monomorphizer import IntMonomorphizer
|
||||||
from .iodelay_estimator import IODelayEstimator
|
from .iodelay_estimator import IODelayEstimator
|
||||||
from .artiq_ir_generator import ARTIQIRGenerator
|
from .artiq_ir_generator import ARTIQIRGenerator
|
||||||
from .dead_code_eliminator import DeadCodeEliminator
|
from .dead_code_eliminator import DeadCodeEliminator
|
||||||
from .cfg_simplifier import CFGSimplifier
|
|
||||||
from .llvm_ir_generator import LLVMIRGenerator
|
from .llvm_ir_generator import LLVMIRGenerator
|
||||||
from .interleaver import Interleaver
|
from .interleaver import Interleaver
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
"""
|
|
||||||
:class:`CFGSimplifier` is a simple control flow graph
|
|
||||||
simplification transform: it removes empty basic blocks.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from .. import ir
|
|
||||||
|
|
||||||
class CFGSimplifier:
|
|
||||||
def __init__(self, engine):
|
|
||||||
self.engine = engine
|
|
||||||
|
|
||||||
def process(self, functions):
|
|
||||||
for func in functions:
|
|
||||||
self.process_function(func)
|
|
||||||
|
|
||||||
def process_function(self, func):
|
|
||||||
for block in list(func.basic_blocks):
|
|
||||||
if len(block.instructions) == 1 and \
|
|
||||||
isinstance(block.terminator(), ir.Branch):
|
|
||||||
successor, = block.successors()
|
|
||||||
|
|
||||||
for insn in set(block.uses):
|
|
||||||
if isinstance(insn, ir.BranchIf) and \
|
|
||||||
((insn.if_true() == block and insn.if_false() == successor) or
|
|
||||||
(insn.if_true() == successor and insn.if_false() == block)):
|
|
||||||
# Our IR doesn't tolerate branch_if %c, %b, %b
|
|
||||||
insn.replace_with(ir.Branch(successor))
|
|
||||||
elif isinstance(insn, ir.Phi):
|
|
||||||
incoming_value = insn.incoming_value_for_block(block)
|
|
||||||
insn.remove_incoming_block(block)
|
|
||||||
for pred in block.predecessors():
|
|
||||||
insn.add_incoming(incoming_value, pred)
|
|
||||||
|
|
||||||
block.replace_all_uses_with(successor)
|
|
||||||
block.erase()
|
|
|
@ -143,11 +143,23 @@ class LocalAccessValidator:
|
||||||
|
|
||||||
def _uninitialized_access(self, insn, var_name, pred_at_fault):
|
def _uninitialized_access(self, insn, var_name, pred_at_fault):
|
||||||
if pred_at_fault is not None:
|
if pred_at_fault is not None:
|
||||||
|
visited = set()
|
||||||
|
possible_preds = [pred_at_fault]
|
||||||
|
|
||||||
uninitialized_loc = None
|
uninitialized_loc = None
|
||||||
for pred_insn in reversed(pred_at_fault.instructions):
|
while uninitialized_loc is None:
|
||||||
|
possible_pred = possible_preds.pop(0)
|
||||||
|
visited.add(possible_pred)
|
||||||
|
|
||||||
|
for pred_insn in reversed(possible_pred.instructions):
|
||||||
if pred_insn.loc is not None:
|
if pred_insn.loc is not None:
|
||||||
uninitialized_loc = pred_insn.loc.begin()
|
uninitialized_loc = pred_insn.loc.begin()
|
||||||
break
|
break
|
||||||
|
|
||||||
|
for block in possible_pred.predecessors():
|
||||||
|
if block not in visited:
|
||||||
|
possible_preds.append(block)
|
||||||
|
|
||||||
assert uninitialized_loc is not None
|
assert uninitialized_loc is not None
|
||||||
|
|
||||||
note = diagnostic.Diagnostic("note",
|
note = diagnostic.Diagnostic("note",
|
||||||
|
|
Loading…
Reference in New Issue