From 6a4033cc3204d6a699f28fa03160ec386812d20e Mon Sep 17 00:00:00 2001 From: startwarfields Date: Tue, 25 Jun 2019 13:45:39 -0700 Subject: [PATCH 01/48] Better Add Loop Type unrolling --- compiler/passes/transforms/loop_unroll.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index aaffd05..faa796a 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -28,6 +28,8 @@ def unroll(self, program: Program) -> Program: # compare to binaryOp item variables = program.functions[root]['blocks'][parent].uses labels = [] + + #check to se self.log.warn(variables) @@ -72,7 +74,7 @@ def unroll(self, program: Program) -> Program: # check variable in l_left or l_right is in bo_defs # EXECUTE if BinaryOps.SUBTRACT == BO.op: - # constant = BO.right + constant = 8 base_instructions = program.functions[root]['blocks'][child].instructions.copy() while constant > 1: @@ -86,12 +88,13 @@ def unroll(self, program: Program) -> Program: # TODO: Better Jump Condition Detect # TODO: FIX NUMBER CITIZENSHIP # constant = label.right - constant = 1 + constant = 0 + self.log.warn(BO.right) base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while constant < 7: + while constant < label.right.value: program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant += 1 + constant += int(BO.right) elif BinaryOps.MULTIPLE == BO.op: pass elif BinaryOps.DIVIDE == BO.op: @@ -108,6 +111,10 @@ def unroll(self, program: Program) -> Program: #except: self.log.warn("No Loops Found in Function") + for root in program.functions: + for block in program.functions[root]['blocks']: + self.log.warn(program.functions[root]['blocks'][block]) + self.log.warn("Loop Unrolling Completed") # Test code showing program post unroll From e5e74ee13aa4896d40b17b79bebc29520d542e00 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Tue, 25 Jun 2019 14:24:31 -0700 Subject: [PATCH 02/48] Better handling of relops for single add use case --- compiler/passes/transforms/loop_unroll.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index faa796a..880176f 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -92,9 +92,20 @@ def unroll(self, program: Program) -> Program: self.log.warn(BO.right) base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while constant < label.right.value: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant += int(BO.right) + keep_looping = True + + while keep_looping: + if label.relop.value == 4: + + if constant < label.right.value - 1: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant += int(BO.right) + else: + keep_looping = False + else: + keep_looping = False + + elif BinaryOps.MULTIPLE == BO.op: pass elif BinaryOps.DIVIDE == BO.op: From 4f26a7de655eca9bbba5cfa3bc8e3f0a92e4b04e Mon Sep 17 00:00:00 2001 From: startwarfields Date: Tue, 25 Jun 2019 14:53:41 -0700 Subject: [PATCH 03/48] Added simple multiple loop unroll. --- compiler/passes/transforms/loop_unroll.py | 44 ++++++++++++++--------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 880176f..cde751c 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -69,44 +69,56 @@ def unroll(self, program: Program) -> Program: self.log.warn("Bad or Infinite Loop Detected... aborting unroll") continue - - + keep_looping = True # check variable in l_left or l_right is in bo_defs # EXECUTE if BinaryOps.SUBTRACT == BO.op: - constant = 8 base_instructions = program.functions[root]['blocks'][child].instructions.copy() while constant > 1: program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant -= 1 elif BinaryOps.ADD == BO.op: - reducer = BO.right - - # Find the constant and find the false-jump - - # TODO: Better Jump Condition Detect - # TODO: FIX NUMBER CITIZENSHIP - # constant = label.right - constant = 0 - self.log.warn(BO.right) - + constant = 1 base_instructions = program.functions[root]['blocks'][child].instructions.copy() - keep_looping = True + while keep_looping: if label.relop.value == 4: - if constant < label.right.value - 1: + if constant < label.right.value: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant += int(BO.right) + else: + keep_looping = False + elif label.relop.value == 0: + if constant == label.right.value: program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant += int(BO.right) else: keep_looping = False else: keep_looping = False + elif BinaryOps.MULTIPLE == BO.op: + constant = 1 + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + while keep_looping: + if label.relop.value == 4: - elif BinaryOps.MULTIPLE == BO.op: + if constant < label.right.value : + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant *= int(BO.right) + else: + keep_looping = False + elif label.relop.value == 0: + if constant == label.right.value: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant *= int(BO.right) + else: + keep_looping = False + else: + keep_looping = False pass elif BinaryOps.DIVIDE == BO.op: pass From c1cdd505d1f5a8772839492f0f92a33aeb44de96 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 10:27:38 -0700 Subject: [PATCH 04/48] Refactored Execute Phase of Loop Unrolling, Next Steps: Cleaner Identify, and Induction Proof for Finite Loops --- compiler/passes/transforms/loop_unroll.py | 209 +++++++++------------- 1 file changed, 87 insertions(+), 122 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index cde751c..d9b96bb 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -10,137 +10,102 @@ def __init__(self): super().__init__("LoopUnravel") self.log.warn("Starting Loop Unrolling.....") + def getCondition(self, RO, x, y): + if RO == RelationalOps.EQUALITY: + return True if x == y else False + elif RO == RelationalOps.NE: + return True if x != y else False + elif RO == RelationalOps.LT: + return True if x < y else False + elif RO == RelationalOps.LTE: + return True if x <= y else False + elif RO == RelationalOps.GT: + return True if x > y else False + elif RO == RelationalOps.GTE: + return True if x >= y else False + else: + return False + + def calculateNewValue(self, BO: BinaryOp, x, y): + if BO.op == BinaryOps.SUBTRACT: + x = x - y + elif BO.op == BinaryOps.ADD: + x = x + y + elif BO.op == BinaryOps.MULTIPLE: + x = x * y + elif BO.op == BinaryOps.DIVIDE: + x = x / y + elif BO.op == BinaryOps.AND: + x = x & y + elif BO.op == BinaryOps.OR: + x = x | y + return x + + # TODO: Use "Induction" to determine finite loops + def inductionProof(self, BO, RO, x, y): + return False + def unroll(self, program: Program) -> Program: global jump for root in program.functions: - #try: - glist = list(nx.find_cycle(program.functions[root]['graph'])) - tlist = list(nx.simple_cycles(program.functions[root]['graph'])) - for item in tlist: - child = item[1] - parent = item[0] - self.log.warn(child) - label = None - BO = None - jump = None - - # remove end char from each item in set. - # compare to binaryOp item - variables = program.functions[root]['blocks'][parent].uses - labels = [] - - - #check to se - - self.log.warn(variables) - for items in program.functions[root]['blocks'][parent].instructions: - if type(items) == Conditional: - self.log.warn("Success") - label = program.functions[root]['blocks'][parent].instructions.pop( - program.functions[root]['blocks'][parent].instructions.index(items)) - labels.append(label) - l_left = label.left - l_right = label.right - else: - pass - # Remove Jumps - self.log.warn(labels) - # CHILD MODIFICATIONS - jump = program.functions[root]['blocks'][child].instructions.pop(-1) - BadLoop = True - for items2 in program.functions[root]['blocks'][child].instructions: - - if type(items2) == BinaryOp: - self.log.warn("Success") - # TODO: Better BinaryOp Chec - # 4 Cases: - BO = program.functions[root]['blocks'][child].instructions.pop( - program.functions[root]['blocks'][child].instructions.index(items2)) - if BO.defs.name[:-1] == l_left.name: - BadLoop = False - elif BO.defs.name[:-1] == l_right.name: - BadLoop = False - - else: - pass - # self.log.warn(jump + "Henlo" ) - if jump is None or label is None or BO is None or BadLoop: - self.log.warn(BadLoop) - self.log.warn("Bad or Infinite Loop Detected... aborting unroll") - continue - - keep_looping = True - # check variable in l_left or l_right is in bo_defs - # EXECUTE - if BinaryOps.SUBTRACT == BO.op: - constant = 8 - base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while constant > 1: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant -= 1 - elif BinaryOps.ADD == BO.op: - constant = 1 - base_instructions = program.functions[root]['blocks'][child].instructions.copy() + tlist = list(nx.simple_cycles(program.functions[root]['graph'])) + for item in tlist: + child = item[1] + parent = item[0] + label = None + binary_operation = None + jump = None + labels = [] + # IDENTIFY + # TODO: Better Identification of Conditionals + # Parent Instructions + for p_instructions in program.functions[root]['blocks'][parent].instructions: + if type(p_instructions) == Conditional: + self.log.warn("Success") + label = program.functions[root]['blocks'][parent].instructions.pop( + program.functions[root]['blocks'][parent].instructions.index(p_instructions)) + labels.append(label) + l_left = label.left + l_right = label.right + else: + pass + # Child Instructions + jump = program.functions[root]['blocks'][child].instructions.pop(-1) + badloop = True + for c_instructions in program.functions[root]['blocks'][child].instructions: + if type(c_instructions) == BinaryOp: + self.log.warn("Success") + # TODO: Better BinaryOp Chec + # 4 Cases: + binary_operation = program.functions[root]['blocks'][child].instructions.pop( + program.functions[root]['blocks'][child].instructions.index(c_instructions)) + if binary_operation.defs.name[:-1] == l_left.name: + badloop = False + elif binary_operation.defs.name[:-1] == l_right.name: + badloop = False + else: + pass + if jump is None or label is None or binary_operation is None or badloop: + self.log.warn("Bad or Infinite Loop Detected... aborting unroll") + continue + # EXECUTE + constant = 1 + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + while self.getCondition(label.relop.value, constant, label.right.value): + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant = self.calculateNewValue(binary_operation, constant, int(binary_operation.right)) + # CLEANUP: Pops Parent, adds jump, redoes the labels. + jump.jumps = label.false_branch + program.functions[root]['blocks'][child].instructions.append(jump) + program.functions[root]['blocks'].pop(parent) + program.functions[root]['blocks'][child].label = label.true_branch + program.functions[root]['blocks'][child].jumps.pop() - - while keep_looping: - if label.relop.value == 4: - - if constant < label.right.value: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant += int(BO.right) - else: - keep_looping = False - elif label.relop.value == 0: - if constant == label.right.value: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant += int(BO.right) - else: - keep_looping = False - else: - keep_looping = False - elif BinaryOps.MULTIPLE == BO.op: - constant = 1 - base_instructions = program.functions[root]['blocks'][child].instructions.copy() - - while keep_looping: - if label.relop.value == 4: - - if constant < label.right.value : - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant *= int(BO.right) - else: - keep_looping = False - elif label.relop.value == 0: - if constant == label.right.value: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant *= int(BO.right) - else: - keep_looping = False - else: - keep_looping = False - pass - elif BinaryOps.DIVIDE == BO.op: - pass - else: - pass - - # CLEANUP: Pops Parent, adds jump, redoes the labels. - jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.append(jump) - program.functions[root]['blocks'].pop(parent) - program.functions[root]['blocks'][child].label = label.true_branch - program.functions[root]['blocks'][child].jumps.pop() - - #except: - self.log.warn("No Loops Found in Function") for root in program.functions: for block in program.functions[root]['blocks']: self.log.warn(program.functions[root]['blocks'][block]) self.log.warn("Loop Unrolling Completed") # Test code showing program post unroll - - return program # Entry Point From 122a7fd77bd8df653a7454c1e0da0731eb18f4d7 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 11:05:19 -0700 Subject: [PATCH 05/48] Induction Method added to determine if loop is finite --- compiler/passes/transforms/loop_unroll.py | 25 ++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index d9b96bb..f1c31d6 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -10,7 +10,7 @@ def __init__(self): super().__init__("LoopUnravel") self.log.warn("Starting Loop Unrolling.....") - def getCondition(self, RO, x, y): + def loop_condition(self, RO, x, y): if RO == RelationalOps.EQUALITY: return True if x == y else False elif RO == RelationalOps.NE: @@ -26,7 +26,7 @@ def getCondition(self, RO, x, y): else: return False - def calculateNewValue(self, BO: BinaryOp, x, y): + def reevaluate(self, BO: BinaryOp, x, y): if BO.op == BinaryOps.SUBTRACT: x = x - y elif BO.op == BinaryOps.ADD: @@ -42,8 +42,15 @@ def calculateNewValue(self, BO: BinaryOp, x, y): return x # TODO: Use "Induction" to determine finite loops - def inductionProof(self, BO, RO, x, y): - return False + def finite_loop(self, bin_op, x, y, z, inductive_step=True): + k = self.reevaluate(bin_op, x, y) + k_delta = k - z + zx_delta = x - z + zk_delta = abs(zx_delta) - abs(k_delta) + if inductive_step : i_step = self.finite_loop(bin_op, k, y, z, False) + else: i_step = True + + return True if zk_delta > 0 and i_step else False def unroll(self, program: Program) -> Program: global jump @@ -75,7 +82,8 @@ def unroll(self, program: Program) -> Program: for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: self.log.warn("Success") - # TODO: Better BinaryOp Chec + # TODO: Better Binar + #IDENTyOp Chec # 4 Cases: binary_operation = program.functions[root]['blocks'][child].instructions.pop( program.functions[root]['blocks'][child].instructions.index(c_instructions)) @@ -89,11 +97,14 @@ def unroll(self, program: Program) -> Program: self.log.warn("Bad or Infinite Loop Detected... aborting unroll") continue # EXECUTE + # Warning 0: This Code Works assuming the right is the constant + # Warning 1: This Code is not fully functional: it cannot find the original x value constant = 1 base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while self.getCondition(label.relop.value, constant, label.right.value): + while self.finite_loop(binary_operation,constant,int(binary_operation.right),label.right.value) \ + and self.loop_condition(label.relop.value, constant, label.right.value): program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant = self.calculateNewValue(binary_operation, constant, int(binary_operation.right)) + constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) # CLEANUP: Pops Parent, adds jump, redoes the labels. jump.jumps = label.false_branch program.functions[root]['blocks'][child].instructions.append(jump) From 9fe77d718f323f7a94a93f612644eff5ec9484cf Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 11:27:52 -0700 Subject: [PATCH 06/48] Loop Unroll correctly resets the instructions of an unrollable loop --- compiler/passes/transforms/loop_unroll.py | 28 ++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index f1c31d6..82b8db1 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -2,6 +2,7 @@ from compiler.data_structures.program import Program from compiler.passes.transforms.bs_transform import BSTransform import networkx as nx +import copy class LoopUnroll(BSTransform): @@ -47,7 +48,7 @@ def finite_loop(self, bin_op, x, y, z, inductive_step=True): k_delta = k - z zx_delta = x - z zk_delta = abs(zx_delta) - abs(k_delta) - if inductive_step : i_step = self.finite_loop(bin_op, k, y, z, False) + if inductive_step: i_step = self.finite_loop(bin_op, k, y, z, False) else: i_step = True return True if zk_delta > 0 and i_step else False @@ -59,6 +60,9 @@ def unroll(self, program: Program) -> Program: for item in tlist: child = item[1] parent = item[0] + + pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) + pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) label = None binary_operation = None jump = None @@ -96,21 +100,29 @@ def unroll(self, program: Program) -> Program: if jump is None or label is None or binary_operation is None or badloop: self.log.warn("Bad or Infinite Loop Detected... aborting unroll") continue + # EXECUTE # Warning 0: This Code Works assuming the right is the constant # Warning 1: This Code is not fully functional: it cannot find the original x value constant = 1 base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while self.finite_loop(binary_operation,constant,int(binary_operation.right),label.right.value) \ - and self.loop_condition(label.relop.value, constant, label.right.value): + is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) + while is_finite & self.loop_condition(label.relop.value, constant, label.right.value): program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) + # CLEANUP: Pops Parent, adds jump, redoes the labels. - jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.append(jump) - program.functions[root]['blocks'].pop(parent) - program.functions[root]['blocks'][child].label = label.true_branch - program.functions[root]['blocks'][child].jumps.pop() + + if is_finite: + jump.jumps = label.false_branch + program.functions[root]['blocks'][child].instructions.append(jump) + program.functions[root]['blocks'].pop(parent) + program.functions[root]['blocks'][child].label = label.true_branch + program.functions[root]['blocks'][child].jumps.pop() + else: + program.functions[root]['blocks'][parent].instructions = pure_parent_ins + program.functions[root]['blocks'][child].instructions = pure_child_ins + for root in program.functions: for block in program.functions[root]['blocks']: From cdd9b3a549ad2caef8a7e6f4d91a734d49b59f3f Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 11:53:04 -0700 Subject: [PATCH 07/48] Bad Loops and Unrollable Loops both handled correctly, small optimizations --- compiler/passes/transforms/loop_unroll.py | 31 ++++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 82b8db1..a6d2813 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -86,9 +86,7 @@ def unroll(self, program: Program) -> Program: for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: self.log.warn("Success") - # TODO: Better Binar - #IDENTyOp Chec - # 4 Cases: + # TODO: Better Binary Detection binary_operation = program.functions[root]['blocks'][child].instructions.pop( program.functions[root]['blocks'][child].instructions.index(c_instructions)) if binary_operation.defs.name[:-1] == l_left.name: @@ -97,31 +95,34 @@ def unroll(self, program: Program) -> Program: badloop = False else: pass - if jump is None or label is None or binary_operation is None or badloop: - self.log.warn("Bad or Infinite Loop Detected... aborting unroll") - continue + if jump is None or label is None or binary_operation is None: + badloop = True # EXECUTE # Warning 0: This Code Works assuming the right is the constant # Warning 1: This Code is not fully functional: it cannot find the original x value - constant = 1 - base_instructions = program.functions[root]['blocks'][child].instructions.copy() - is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) - while is_finite & self.loop_condition(label.relop.value, constant, label.right.value): - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) - - # CLEANUP: Pops Parent, adds jump, redoes the labels. - + if badloop is False: + constant = 1 + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), + label.right.value) if is_finite: + while self.loop_condition(label.relop.value, constant, label.right.value): + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) + # CLEANUP: Pops Parent, adds jump, redoes the labels. jump.jumps = label.false_branch program.functions[root]['blocks'][child].instructions.append(jump) program.functions[root]['blocks'].pop(parent) program.functions[root]['blocks'][child].label = label.true_branch program.functions[root]['blocks'][child].jumps.pop() else: + badloop = True + + if badloop: program.functions[root]['blocks'][parent].instructions = pure_parent_ins program.functions[root]['blocks'][child].instructions = pure_child_ins + self.log.warn("Found Unrollable Loop... resetting instructions..") for root in program.functions: From dc7db84442c707386f70cd994446f143f946a183 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 14:13:44 -0700 Subject: [PATCH 08/48] Conditionals Work Correctly, however nested conditionals imply a control loop, which is not done by loop unrolling. --- compiler/passes/transforms/loop_unroll.py | 43 ++++++++++++++--------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index a6d2813..c3c1404 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -57,12 +57,17 @@ def unroll(self, program: Program) -> Program: global jump for root in program.functions: tlist = list(nx.simple_cycles(program.functions[root]['graph'])) + self.log.warn(tlist) for item in tlist: + if len(item) > 2: + continue child = item[1] parent = item[0] pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) + c_label = program.functions[root]['blocks'][child].label + label = None binary_operation = None jump = None @@ -72,17 +77,21 @@ def unroll(self, program: Program) -> Program: # Parent Instructions for p_instructions in program.functions[root]['blocks'][parent].instructions: if type(p_instructions) == Conditional: - self.log.warn("Success") - label = program.functions[root]['blocks'][parent].instructions.pop( - program.functions[root]['blocks'][parent].instructions.index(p_instructions)) - labels.append(label) - l_left = label.left - l_right = label.right + if c_label == p_instructions.true_branch: + + self.log.warn("Success") + label = program.functions[root]['blocks'][parent].instructions.pop( + program.functions[root]['blocks'][parent].instructions.index(p_instructions)) + labels.append(label) + l_left = label.left + l_right = label.right else: pass + + + bad_loop = True # Child Instructions jump = program.functions[root]['blocks'][child].instructions.pop(-1) - badloop = True for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: self.log.warn("Success") @@ -90,18 +99,20 @@ def unroll(self, program: Program) -> Program: binary_operation = program.functions[root]['blocks'][child].instructions.pop( program.functions[root]['blocks'][child].instructions.index(c_instructions)) if binary_operation.defs.name[:-1] == l_left.name: - badloop = False + bad_loop = False elif binary_operation.defs.name[:-1] == l_right.name: - badloop = False + bad_loop = False else: pass if jump is None or label is None or binary_operation is None: - badloop = True + bad_loop = True # EXECUTE - # Warning 0: This Code Works assuming the right is the constant + # Warning 0: This Code Works as + #IDENTyOp Chec + # 4 Cases:suming the right is the constant # Warning 1: This Code is not fully functional: it cannot find the original x value - if badloop is False: + if bad_loop is False: constant = 1 base_instructions = program.functions[root]['blocks'][child].instructions.copy() is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), @@ -117,14 +128,12 @@ def unroll(self, program: Program) -> Program: program.functions[root]['blocks'][child].label = label.true_branch program.functions[root]['blocks'][child].jumps.pop() else: - badloop = True + bad_loop = True - if badloop: + if bad_loop: program.functions[root]['blocks'][parent].instructions = pure_parent_ins program.functions[root]['blocks'][child].instructions = pure_child_ins self.log.warn("Found Unrollable Loop... resetting instructions..") - - for root in program.functions: for block in program.functions[root]['blocks']: self.log.warn(program.functions[root]['blocks'][block]) @@ -133,6 +142,8 @@ def unroll(self, program: Program) -> Program: return program # Entry Point + + def transform(self, program: Program) -> Program: for root in program.functions: for block in program.functions[root]['blocks']: From f9af31efbdf6a00e5a4b714aafb3cf46ec576ae4 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 15:31:11 -0700 Subject: [PATCH 09/48] Added Crash Prevention for Nested While Loops. Nested Loops do not unroll though --- compiler/passes/transforms/loop_unroll.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index c3c1404..f4f4b5c 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -63,7 +63,8 @@ def unroll(self, program: Program) -> Program: continue child = item[1] parent = item[0] - + self.log.warn(child) + self.log.warn(program.functions[root]['blocks'][1]) pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) c_label = program.functions[root]['blocks'][child].label @@ -75,6 +76,7 @@ def unroll(self, program: Program) -> Program: # IDENTIFY # TODO: Better Identification of Conditionals # Parent Instructions + l_left = l_right = None for p_instructions in program.functions[root]['blocks'][parent].instructions: if type(p_instructions) == Conditional: if c_label == p_instructions.true_branch: @@ -87,10 +89,9 @@ def unroll(self, program: Program) -> Program: l_right = label.right else: pass - - bad_loop = True # Child Instructions + jump = program.functions[root]['blocks'][child].instructions.pop(-1) for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: @@ -98,9 +99,9 @@ def unroll(self, program: Program) -> Program: # TODO: Better Binary Detection binary_operation = program.functions[root]['blocks'][child].instructions.pop( program.functions[root]['blocks'][child].instructions.index(c_instructions)) - if binary_operation.defs.name[:-1] == l_left.name: + if l_left != None and binary_operation.defs.name[:-1] == l_left.name: bad_loop = False - elif binary_operation.defs.name[:-1] == l_right.name: + elif l_right != None and binary_operation.defs.name[:-1] == l_right.name: bad_loop = False else: pass @@ -112,6 +113,7 @@ def unroll(self, program: Program) -> Program: #IDENTyOp Chec # 4 Cases:suming the right is the constant # Warning 1: This Code is not fully functional: it cannot find the original x value + is_finite = False if bad_loop is False: constant = 1 base_instructions = program.functions[root]['blocks'][child].instructions.copy() From 38ef34438e224da5b3e54e651868afc8c95fd547 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 15:39:32 -0700 Subject: [PATCH 10/48] Pre-Demo Milestone 1 Commit --- compiler/passes/transforms/loop_unroll.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index f4f4b5c..053f6e9 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -42,7 +42,6 @@ def reevaluate(self, BO: BinaryOp, x, y): x = x | y return x - # TODO: Use "Induction" to determine finite loops def finite_loop(self, bin_op, x, y, z, inductive_step=True): k = self.reevaluate(bin_op, x, y) k_delta = k - z @@ -57,14 +56,11 @@ def unroll(self, program: Program) -> Program: global jump for root in program.functions: tlist = list(nx.simple_cycles(program.functions[root]['graph'])) - self.log.warn(tlist) for item in tlist: if len(item) > 2: continue child = item[1] parent = item[0] - self.log.warn(child) - self.log.warn(program.functions[root]['blocks'][1]) pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) c_label = program.functions[root]['blocks'][child].label @@ -74,7 +70,7 @@ def unroll(self, program: Program) -> Program: jump = None labels = [] # IDENTIFY - # TODO: Better Identification of Conditionals + # Parent Instructions l_left = l_right = None for p_instructions in program.functions[root]['blocks'][parent].instructions: @@ -144,8 +140,6 @@ def unroll(self, program: Program) -> Program: return program # Entry Point - - def transform(self, program: Program) -> Program: for root in program.functions: for block in program.functions[root]['blocks']: From eb6e9f03c191930c1f8e577a45bdc920036bba66 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 1 Jul 2019 16:14:14 -0700 Subject: [PATCH 11/48] Planning Steps for Upgrading Identify stage to correctly identify all loops, not just cycles --- compiler/passes/transforms/loop_unroll.py | 24 +++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 053f6e9..c4ae843 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -51,16 +51,35 @@ def finite_loop(self, bin_op, x, y, z, inductive_step=True): else: i_step = True return True if zk_delta > 0 and i_step else False + def give_graph_loop(self,tlist): + # Algorithm Steps + # Let s be a set of nodes including header node h + # 1) for every node in s there is a path to h + # 2) from h there is a path to every node in s + # 3) there is no edge from any node outside S to any node in S other than h + + l_list = [] + return l_list def unroll(self, program: Program) -> Program: global jump for root in program.functions: + tlist = list(nx.simple_cycles(program.functions[root]['graph'])) + node_one = list(nx.nodes(program.functions[root]['graph'])) + # Step 1: Get cycle + # Step 2: Analyze Cycle + # This helps us verify condition 3: No outsinde inc edges + glist = program.functions[root]['graph'].in_edges(node_one[1]) + + self.log.warn(glist) + self.log.warn(tlist) for item in tlist: if len(item) > 2: continue child = item[1] parent = item[0] + pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) c_label = program.functions[root]['blocks'][child].label @@ -69,7 +88,7 @@ def unroll(self, program: Program) -> Program: binary_operation = None jump = None labels = [] - # IDENTIFY + # IDENTIFY - rewrite to implement dominator algorithm # Parent Instructions l_left = l_right = None @@ -111,7 +130,8 @@ def unroll(self, program: Program) -> Program: # Warning 1: This Code is not fully functional: it cannot find the original x value is_finite = False if bad_loop is False: - constant = 1 + constant = 1 # Can't get current variable value, assume 1 because we already have 1 "set" + # of instructions base_instructions = program.functions[root]['blocks'][child].instructions.copy() is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) From b7ca83cd15b82159677ce910adeac5b38f5035ee Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 3 Jul 2019 12:19:22 -0700 Subject: [PATCH 12/48] Fixed Flow from Header to body in unrolled loops in the clean-up stage --- compiler/passes/transforms/loop_unroll.py | 24 ++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index c4ae843..c6b7185 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -5,6 +5,7 @@ import copy + class LoopUnroll(BSTransform): def __init__(self): @@ -51,15 +52,19 @@ def finite_loop(self, bin_op, x, y, z, inductive_step=True): else: i_step = True return True if zk_delta > 0 and i_step else False - def give_graph_loop(self,tlist): + def give_graph_loop(self,node_list): # Algorithm Steps - # Let s be a set of nodes including header node h - # 1) for every node in s there is a path to h - # 2) from h there is a path to every node in s - # 3) there is no edge from any node outside S to any node in S other than h - - l_list = [] - return l_list + # Given a list of cycles + # 1) for each item ,determine if the cycle is a loop + # 2) if all nodes of a loop are contained within another loop, + # put the smaller loop in front of the bigger loop in the order + # + for node in node_list: + # node_item = + # node_incoming = + + + return True def unroll(self, program: Program) -> Program: global jump @@ -142,7 +147,8 @@ def unroll(self, program: Program) -> Program: # CLEANUP: Pops Parent, adds jump, redoes the labels. jump.jumps = label.false_branch program.functions[root]['blocks'][child].instructions.append(jump) - program.functions[root]['blocks'].pop(parent) + jumpy = Jump(label.true_branch) + program.functions[root]['blocks'][parent].instructions.append(jumpy) program.functions[root]['blocks'][child].label = label.true_branch program.functions[root]['blocks'][child].jumps.pop() else: From 16e4887d680f35694f3d50f297872f511fc28f65 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 3 Jul 2019 15:55:45 -0700 Subject: [PATCH 13/48] Loop Identification via dominators completed. Nested While Loops Work, Nested Conditionals, Multiple Conditionals, Multiple Loops --- compiler/passes/transforms/loop_unroll.py | 42 ++++++++++++----------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index c6b7185..34eb0f9 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -52,38 +52,41 @@ def finite_loop(self, bin_op, x, y, z, inductive_step=True): else: i_step = True return True if zk_delta > 0 and i_step else False - def give_graph_loop(self,node_list): + def give_loop_order(self,node_list): # Algorithm Steps - # Given a list of cycles - # 1) for each item ,determine if the cycle is a loop - # 2) if all nodes of a loop are contained within another loop, - # put the smaller loop in front of the bigger loop in the order - # - for node in node_list: - # node_item = - # node_incoming = - - - return True + # Detect: + # Get Immediate Dominators for every node + # Detect back-edges on each node + # Construct loop using intersection of ancestors of body and descendents of h + # Put loop set into list. + # Order loop list by non-containing nested first. + return node_list def unroll(self, program: Program) -> Program: global jump for root in program.functions: - tlist = list(nx.simple_cycles(program.functions[root]['graph'])) + tlist = [] node_one = list(nx.nodes(program.functions[root]['graph'])) + dominators = (nx.immediate_dominators(program.functions[root]['graph'],1)) + sorted_doms = sorted(dominators.items()) + for item in dominators: + edge_list = list(program.functions[root]['graph'].out_edges(item)) + if len(edge_list) > 0: + for edge in edge_list: + if edge in sorted_doms: + tlist.append(edge) + + # Step 1: Get cycle # Step 2: Analyze Cycle # This helps us verify condition 3: No outsinde inc edges - glist = program.functions[root]['graph'].in_edges(node_one[1]) - self.log.warn(glist) - self.log.warn(tlist) for item in tlist: if len(item) > 2: continue - child = item[1] - parent = item[0] + child = item[0] + parent = item[1] pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) @@ -101,7 +104,7 @@ def unroll(self, program: Program) -> Program: if type(p_instructions) == Conditional: if c_label == p_instructions.true_branch: - self.log.warn("Success") + label = program.functions[root]['blocks'][parent].instructions.pop( program.functions[root]['blocks'][parent].instructions.index(p_instructions)) labels.append(label) @@ -115,7 +118,6 @@ def unroll(self, program: Program) -> Program: jump = program.functions[root]['blocks'][child].instructions.pop(-1) for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: - self.log.warn("Success") # TODO: Better Binary Detection binary_operation = program.functions[root]['blocks'][child].instructions.pop( program.functions[root]['blocks'][child].instructions.index(c_instructions)) From 59177cfede4c89d71eec14d121a651bdec53c5eb Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 3 Jul 2019 15:59:55 -0700 Subject: [PATCH 14/48] Minor Edits. Removed Herobrine --- compiler/passes/transforms/loop_unroll.py | 28 +++++------------------ 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 34eb0f9..fb6d30e 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -52,15 +52,6 @@ def finite_loop(self, bin_op, x, y, z, inductive_step=True): else: i_step = True return True if zk_delta > 0 and i_step else False - def give_loop_order(self,node_list): - # Algorithm Steps - # Detect: - # Get Immediate Dominators for every node - # Detect back-edges on each node - # Construct loop using intersection of ancestors of body and descendents of h - # Put loop set into list. - # Order loop list by non-containing nested first. - return node_list def unroll(self, program: Program) -> Program: global jump @@ -77,11 +68,6 @@ def unroll(self, program: Program) -> Program: if edge in sorted_doms: tlist.append(edge) - - # Step 1: Get cycle - # Step 2: Analyze Cycle - # This helps us verify condition 3: No outsinde inc edges - for item in tlist: if len(item) > 2: continue @@ -103,8 +89,6 @@ def unroll(self, program: Program) -> Program: for p_instructions in program.functions[root]['blocks'][parent].instructions: if type(p_instructions) == Conditional: if c_label == p_instructions.true_branch: - - label = program.functions[root]['blocks'][parent].instructions.pop( program.functions[root]['blocks'][parent].instructions.index(p_instructions)) labels.append(label) @@ -114,7 +98,6 @@ def unroll(self, program: Program) -> Program: pass bad_loop = True # Child Instructions - jump = program.functions[root]['blocks'][child].instructions.pop(-1) for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: @@ -132,13 +115,14 @@ def unroll(self, program: Program) -> Program: # EXECUTE # Warning 0: This Code Works as - #IDENTyOp Chec - # 4 Cases:suming the right is the constant + # IDENTyOp Chec + # 4 Cases:suming the right is the constant # Warning 1: This Code is not fully functional: it cannot find the original x value is_finite = False if bad_loop is False: - constant = 1 # Can't get current variable value, assume 1 because we already have 1 "set" - # of instructions + constant = 1 + # Can't get current variable value, assume 1 because we already have 1 "set" + # of instructions base_instructions = program.functions[root]['blocks'][child].instructions.copy() is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) @@ -149,7 +133,7 @@ def unroll(self, program: Program) -> Program: # CLEANUP: Pops Parent, adds jump, redoes the labels. jump.jumps = label.false_branch program.functions[root]['blocks'][child].instructions.append(jump) - jumpy = Jump(label.true_branch) + jumpy = Jump(label.true_branch) program.functions[root]['blocks'][parent].instructions.append(jumpy) program.functions[root]['blocks'][child].label = label.true_branch program.functions[root]['blocks'][child].jumps.pop() From 9fc57b6a53e6c6d6ca6ecbeaf3531f265f98ffa5 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 8 Jul 2019 12:30:24 -0700 Subject: [PATCH 15/48] Fixed While Loop Labels, Updated Loop Unrolling --- compiler/passes/transforms/loop_unroll.py | 33 +++++++++++++++++------ compiler/semantics/ir_visitor.py | 6 ++--- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index fb6d30e..0b738aa 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -88,29 +88,40 @@ def unroll(self, program: Program) -> Program: l_left = l_right = None for p_instructions in program.functions[root]['blocks'][parent].instructions: if type(p_instructions) == Conditional: - if c_label == p_instructions.true_branch: + if c_label.label == p_instructions.true_branch.label: label = program.functions[root]['blocks'][parent].instructions.pop( program.functions[root]['blocks'][parent].instructions.index(p_instructions)) + self.log.warn(label) labels.append(label) l_left = label.left + l_right = label.right + else: + self.log.warn(p_instructions.true_branch) + self.log.warn(c_label) + self.log.warn(p_instructions.true_branch == c_label) else: pass bad_loop = True # Child Instructions - jump = program.functions[root]['blocks'][child].instructions.pop(-1) + # TODO: Fix Child end Jump Detection + if program.functions[root]['blocks'][child].instructions[-1] == Jump: + jump = program.functions[root]['blocks'][child].instructions.pop(-1) + else: + jump = None for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: - # TODO: Better Binary Detection - binary_operation = program.functions[root]['blocks'][child].instructions.pop( - program.functions[root]['blocks'][child].instructions.index(c_instructions)) + binary_operation = c_instructions if l_left != None and binary_operation.defs.name[:-1] == l_left.name: + program.functions[root]['blocks'][child].instructions.pop(program.functions[root]['blocks'][child].instructions.index(c_instructions)) bad_loop = False elif l_right != None and binary_operation.defs.name[:-1] == l_right.name: + program.functions[root]['blocks'][child].instructions.pop(program.functions[root]['blocks'][child].instructions.index(c_instructions)) bad_loop = False else: pass - if jump is None or label is None or binary_operation is None: + if label is None or binary_operation is None: + self.log.warn("I fail on the initial bad loop!") bad_loop = True # EXECUTE @@ -120,6 +131,7 @@ def unroll(self, program: Program) -> Program: # Warning 1: This Code is not fully functional: it cannot find the original x value is_finite = False if bad_loop is False: + self.log.warn("I fail on the binaryop check!") constant = 1 # Can't get current variable value, assume 1 because we already have 1 "set" # of instructions @@ -131,13 +143,18 @@ def unroll(self, program: Program) -> Program: program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) # CLEANUP: Pops Parent, adds jump, redoes the labels. - jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.append(jump) + + if jump is not None: + jump.jumps = label.false_branch + program.functions[root]['blocks'][child].instructions.append(jump) + jumpy = Jump(label.true_branch) program.functions[root]['blocks'][parent].instructions.append(jumpy) program.functions[root]['blocks'][child].label = label.true_branch + program.functions[root]['blocks'][child].jumps.pop() else: + self.log.warn("I fail on the finite check!") bad_loop = True if bad_loop: diff --git a/compiler/semantics/ir_visitor.py b/compiler/semantics/ir_visitor.py index 62c722f..de20be0 100644 --- a/compiler/semantics/ir_visitor.py +++ b/compiler/semantics/ir_visitor.py @@ -265,7 +265,7 @@ def visitWhileStatement(self, ctx: BSParser.WhileStatementContext): self.scope_stack[-1], value=float(par_expression['exp2']), is_constant=True) self.symbol_table.add_local(exp2, self.scope_stack[-1]) else: - exp2 = par_expression['exp2'] + exp2 = self.allocation_map[par_expression['exp2']] pre_condition_label_string = "bsbbw_{}_l".format(self.current_block.nid) pre_condition_label = Label(pre_condition_label_string) @@ -276,7 +276,7 @@ def visitWhileStatement(self, ctx: BSParser.WhileStatementContext): condition = Conditional(par_expression['op'], exp1, exp2) true_block = BasicBlock() self.graph.add_node(true_block.nid, function=self.scope_stack[-1]) - true_label = Label("bsbbw_{}_t".format(self.current_block.nid)) + true_label = Label("bsbbw_{}_l".format(true_block.nid)) self.labels[true_label.name] = true_block.nid true_block.add(true_label) @@ -361,7 +361,7 @@ def visitRepeat(self, ctx: BSParser.RepeatContext): condition = Conditional(par_expression['op'], exp1, exp2) true_block = BasicBlock() self.graph.add_node(true_block.nid, function=self.scope_stack[-1]) - true_label = Label("bsbbw_{}_t".format(self.current_block.nid)) + true_label = Label("bsbbw_{}_l".format(true_block.nid)) self.labels[true_label.name] = true_block.nid true_block.add(true_label) From 8acfa6146ac542d6ac79c162f7ab65d4bf19c58a Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 8 Jul 2019 12:40:39 -0700 Subject: [PATCH 16/48] Fixed Nested Loop Multipliers --- compiler/passes/transforms/loop_unroll.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 0b738aa..8b97611 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -83,7 +83,7 @@ def unroll(self, program: Program) -> Program: jump = None labels = [] # IDENTIFY - rewrite to implement dominator algorithm - + nested_multiplier = 0 # Parent Instructions l_left = l_right = None for p_instructions in program.functions[root]['blocks'][parent].instructions: @@ -91,15 +91,12 @@ def unroll(self, program: Program) -> Program: if c_label.label == p_instructions.true_branch.label: label = program.functions[root]['blocks'][parent].instructions.pop( program.functions[root]['blocks'][parent].instructions.index(p_instructions)) - self.log.warn(label) + nested_multiplier +=1 labels.append(label) l_left = label.left l_right = label.right - else: - self.log.warn(p_instructions.true_branch) - self.log.warn(c_label) - self.log.warn(p_instructions.true_branch == c_label) + else: pass bad_loop = True @@ -121,7 +118,6 @@ def unroll(self, program: Program) -> Program: else: pass if label is None or binary_operation is None: - self.log.warn("I fail on the initial bad loop!") bad_loop = True # EXECUTE @@ -131,7 +127,6 @@ def unroll(self, program: Program) -> Program: # Warning 1: This Code is not fully functional: it cannot find the original x value is_finite = False if bad_loop is False: - self.log.warn("I fail on the binaryop check!") constant = 1 # Can't get current variable value, assume 1 because we already have 1 "set" # of instructions @@ -139,7 +134,7 @@ def unroll(self, program: Program) -> Program: is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) if is_finite: - while self.loop_condition(label.relop.value, constant, label.right.value): + while self.loop_condition(label.relop.value, constant, label.right.value*nested_multiplier): program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) # CLEANUP: Pops Parent, adds jump, redoes the labels. @@ -154,7 +149,6 @@ def unroll(self, program: Program) -> Program: program.functions[root]['blocks'][child].jumps.pop() else: - self.log.warn("I fail on the finite check!") bad_loop = True if bad_loop: From 715761c05a0b918da7d3ecffe8fcce05ede71f07 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 8 Jul 2019 13:28:17 -0700 Subject: [PATCH 17/48] Refactored Jump handling in loops --- compiler/passes/transforms/loop_unroll.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 8b97611..852b694 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -130,24 +130,26 @@ def unroll(self, program: Program) -> Program: constant = 1 # Can't get current variable value, assume 1 because we already have 1 "set" # of instructions - base_instructions = program.functions[root]['blocks'][child].instructions.copy() + base_instructions_unf = program.functions[root]['blocks'][child].instructions.copy() + base_instructions = list(filter(lambda i : not(type(i) is Jump), base_instructions_unf)) + program.functions[root]['blocks'][child].instructions = base_instructions.copy() is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) if is_finite: while self.loop_condition(label.relop.value, constant, label.right.value*nested_multiplier): - program.functions[root]['blocks'][child].instructions.extend(base_instructions) + program.functions[root]['blocks'][child].instructions +=base_instructions constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) # CLEANUP: Pops Parent, adds jump, redoes the labels. - if jump is not None: jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.append(jump) + program.functions[root]['blocks'][child].instructions.extend(jump) jumpy = Jump(label.true_branch) program.functions[root]['blocks'][parent].instructions.append(jumpy) program.functions[root]['blocks'][child].label = label.true_branch program.functions[root]['blocks'][child].jumps.pop() + program.functions[root]['blocks'][child].instructions.append(Jump(program.functions[root]['blocks'][child+1].label)) else: bad_loop = True From 5982ed99a951c7ebb54ab168f8cb7de117b9da17 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 8 Jul 2019 13:54:31 -0700 Subject: [PATCH 18/48] Pre-Pull Request Code Cleanup --- compiler/passes/transforms/loop_unroll.py | 177 ++++++++++------------ 1 file changed, 84 insertions(+), 93 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 852b694..9dc0854 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -12,85 +12,84 @@ def __init__(self): super().__init__("LoopUnravel") self.log.warn("Starting Loop Unrolling.....") - def loop_condition(self, RO, x, y): - if RO == RelationalOps.EQUALITY: - return True if x == y else False - elif RO == RelationalOps.NE: - return True if x != y else False - elif RO == RelationalOps.LT: - return True if x < y else False - elif RO == RelationalOps.LTE: - return True if x <= y else False - elif RO == RelationalOps.GT: - return True if x > y else False - elif RO == RelationalOps.GTE: - return True if x >= y else False + def loop_condition(self, RelOp, left, right): + if RelOp == RelationalOps.EQUALITY: + return True if left == right else False + elif RelOp == RelationalOps.NE: + return True if left != right else False + elif RelOp == RelationalOps.LT: + return True if left < right else False + elif RelOp == RelationalOps.LTE: + return True if left <= right else False + elif RelOp == RelationalOps.GT: + return True if left > right else False + elif RelOp == RelationalOps.GTE: + return True if left >= right else False else: return False - def reevaluate(self, BO: BinaryOp, x, y): - if BO.op == BinaryOps.SUBTRACT: - x = x - y - elif BO.op == BinaryOps.ADD: - x = x + y - elif BO.op == BinaryOps.MULTIPLE: - x = x * y - elif BO.op == BinaryOps.DIVIDE: - x = x / y - elif BO.op == BinaryOps.AND: - x = x & y - elif BO.op == BinaryOps.OR: - x = x | y - return x - - def finite_loop(self, bin_op, x, y, z, inductive_step=True): - k = self.reevaluate(bin_op, x, y) - k_delta = k - z - zx_delta = x - z - zk_delta = abs(zx_delta) - abs(k_delta) - if inductive_step: i_step = self.finite_loop(bin_op, k, y, z, False) + def reevaluate(self, BinOp: BinaryOp, left, right): + if BinOp.op == BinaryOps.SUBTRACT: + left = left - right + elif BinOp.op == BinaryOps.ADD: + left = left + right + elif BinOp.op == BinaryOps.MULTIPLE: + left = left * right + elif BinOp.op == BinaryOps.DIVIDE: + left = left / right + elif BinOp.op == BinaryOps.AND: + left = left & right + elif BinOp.op == BinaryOps.OR: + left = left | right + return left + + def finite_loop(self, bin_op, left: int, modifier: int, right: int, inductive_step=True): + left_modified = self.reevaluate(bin_op, left, modifier) + left_modified_right_delta = left_modified - right + left_right_delta = left - right + lmrd_lrd_delta = left_right_delta - left_modified_right_delta + if inductive_step: i_step = self.finite_loop(bin_op, left_modified, modifier, right, False) else: i_step = True - return True if zk_delta > 0 and i_step else False + return True if abs(lmrd_lrd_delta) > 0 and i_step else False def unroll(self, program: Program) -> Program: - global jump + global jump_from_loop_body for root in program.functions: - tlist = [] - node_one = list(nx.nodes(program.functions[root]['graph'])) + loop_list = [] dominators = (nx.immediate_dominators(program.functions[root]['graph'],1)) sorted_doms = sorted(dominators.items()) - for item in dominators: - edge_list = list(program.functions[root]['graph'].out_edges(item)) + for loop in dominators: + edge_list = list(program.functions[root]['graph'].out_edges(loop)) if len(edge_list) > 0: for edge in edge_list: if edge in sorted_doms: - tlist.append(edge) + loop_list.append(edge) - for item in tlist: - if len(item) > 2: + for loop in loop_list: + if len(loop) > 2: continue - child = item[0] - parent = item[1] + loop_body = loop[0] + head = loop[1] - pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) - pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) - c_label = program.functions[root]['blocks'][child].label + pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][loop_body].instructions) + pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][head].instructions) + c_label = program.functions[root]['blocks'][loop_body].label label = None binary_operation = None - jump = None + jump_from_loop_body = None labels = [] - # IDENTIFY - rewrite to implement dominator algorithm + # IDENTIFY nested_multiplier = 0 - # Parent Instructions + # Head Instructions l_left = l_right = None - for p_instructions in program.functions[root]['blocks'][parent].instructions: + for p_instructions in program.functions[root]['blocks'][head].instructions: if type(p_instructions) == Conditional: if c_label.label == p_instructions.true_branch.label: - label = program.functions[root]['blocks'][parent].instructions.pop( - program.functions[root]['blocks'][parent].instructions.index(p_instructions)) + label = program.functions[root]['blocks'][head].instructions.pop( + program.functions[root]['blocks'][head].instructions.index(p_instructions)) nested_multiplier +=1 labels.append(label) l_left = label.left @@ -100,20 +99,19 @@ def unroll(self, program: Program) -> Program: else: pass bad_loop = True - # Child Instructions - # TODO: Fix Child end Jump Detection - if program.functions[root]['blocks'][child].instructions[-1] == Jump: - jump = program.functions[root]['blocks'][child].instructions.pop(-1) + + if program.functions[root]['blocks'][loop_body].instructions[-1] == Jump: + jump_from_loop_body = program.functions[root]['blocks'][loop_body].instructions.pop(-1) else: - jump = None - for c_instructions in program.functions[root]['blocks'][child].instructions: + jump_from_loop_body = None + for c_instructions in program.functions[root]['blocks'][loop_body].instructions: if type(c_instructions) == BinaryOp: binary_operation = c_instructions if l_left != None and binary_operation.defs.name[:-1] == l_left.name: - program.functions[root]['blocks'][child].instructions.pop(program.functions[root]['blocks'][child].instructions.index(c_instructions)) + program.functions[root]['blocks'][loop_body].instructions.pop(program.functions[root]['blocks'][loop_body].instructions.index(c_instructions)) bad_loop = False elif l_right != None and binary_operation.defs.name[:-1] == l_right.name: - program.functions[root]['blocks'][child].instructions.pop(program.functions[root]['blocks'][child].instructions.index(c_instructions)) + program.functions[root]['blocks'][loop_body].instructions.pop(program.functions[root]['blocks'][loop_body].instructions.index(c_instructions)) bad_loop = False else: pass @@ -121,55 +119,48 @@ def unroll(self, program: Program) -> Program: bad_loop = True # EXECUTE - # Warning 0: This Code Works as - # IDENTyOp Chec - # 4 Cases:suming the right is the constant - # Warning 1: This Code is not fully functional: it cannot find the original x value + # TODO: Refactor when Numbers are fixed is_finite = False if bad_loop is False: constant = 1 - # Can't get current variable value, assume 1 because we already have 1 "set" - # of instructions - base_instructions_unf = program.functions[root]['blocks'][child].instructions.copy() + + base_instructions_unf = program.functions[root]['blocks'][loop_body].instructions.copy() base_instructions = list(filter(lambda i : not(type(i) is Jump), base_instructions_unf)) - program.functions[root]['blocks'][child].instructions = base_instructions.copy() + program.functions[root]['blocks'][loop_body].instructions = base_instructions.copy() is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) if is_finite: while self.loop_condition(label.relop.value, constant, label.right.value*nested_multiplier): - program.functions[root]['blocks'][child].instructions +=base_instructions + program.functions[root]['blocks'][loop_body].instructions +=base_instructions constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) - # CLEANUP: Pops Parent, adds jump, redoes the labels. - if jump is not None: - jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.extend(jump) + # CLEANUP: Adds the correct jump paths + if jump_from_loop_body is not None: + jump_from_loop_body.jumps = label.false_branch + program.functions[root]['blocks'][loop_body].instructions.extend(jump_from_loop_body) - jumpy = Jump(label.true_branch) - program.functions[root]['blocks'][parent].instructions.append(jumpy) - program.functions[root]['blocks'][child].label = label.true_branch + jump_from_head = Jump(label.true_branch) + program.functions[root]['blocks'][head].instructions.append(jump_from_head) + program.functions[root]['blocks'][loop_body].label = label.true_branch - program.functions[root]['blocks'][child].jumps.pop() - program.functions[root]['blocks'][child].instructions.append(Jump(program.functions[root]['blocks'][child+1].label)) + program.functions[root]['blocks'][loop_body].jumps.pop() + program.functions[root]['blocks'][loop_body].instructions.append(Jump(program.functions[root]['blocks'][loop_body+1].label)) else: bad_loop = True if bad_loop: - program.functions[root]['blocks'][parent].instructions = pure_parent_ins - program.functions[root]['blocks'][child].instructions = pure_child_ins + program.functions[root]['blocks'][head].instructions = pure_parent_ins + program.functions[root]['blocks'][loop_body].instructions = pure_child_ins self.log.warn("Found Unrollable Loop... resetting instructions..") - for root in program.functions: - for block in program.functions[root]['blocks']: - self.log.warn(program.functions[root]['blocks'][block]) - self.log.warn("Loop Unrolling Completed") - # Test code showing program post unroll + # for root in program.functions: + # for block in program.functions[root]['blocks']: + # self.log.warn(program.functions[root]['blocks'][block]) + # self.log.warn("Loop Unrolling Completed") return program # Entry Point def transform(self, program: Program) -> Program: - for root in program.functions: - for block in program.functions[root]['blocks']: - self.log.warn(program.functions[root]['blocks'][block]) - self.log.warn("Loop Unrolling Completed") - # Test Print to show pre-unroll - # Test function + # for root in program.functions: + # for block in program.functions[root]['blocks']: + # self.log.warn(program.functions[root]['blocks'][block]) + # self.log.warn("Loop Unrolling Completed") return self.unroll(program) From 2cd0163fc4478a6b6fd16fd15a473ef1b820ca94 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 8 Jul 2019 13:59:18 -0700 Subject: [PATCH 19/48] Revert exp2 change in visit_while --- compiler/semantics/ir_visitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semantics/ir_visitor.py b/compiler/semantics/ir_visitor.py index de20be0..fc9284d 100644 --- a/compiler/semantics/ir_visitor.py +++ b/compiler/semantics/ir_visitor.py @@ -265,7 +265,7 @@ def visitWhileStatement(self, ctx: BSParser.WhileStatementContext): self.scope_stack[-1], value=float(par_expression['exp2']), is_constant=True) self.symbol_table.add_local(exp2, self.scope_stack[-1]) else: - exp2 = self.allocation_map[par_expression['exp2']] + exp2 = par_expression['exp2'] pre_condition_label_string = "bsbbw_{}_l".format(self.current_block.nid) pre_condition_label = Label(pre_condition_label_string) From e66f9514bcc1fd0195b819682f1613091aceaa6e Mon Sep 17 00:00:00 2001 From: startwarfields Date: Tue, 18 Jun 2019 14:25:47 -0700 Subject: [PATCH 20/48] Basic Hardcoded Loop Unrollling DONE. Split Edges changed return pass to return program NEEDED TO PREVENT ERRORS --- compiler/passes/pass_manager.py | 2 + compiler/passes/transforms/loop_unroll.py | 101 ++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 compiler/passes/transforms/loop_unroll.py diff --git a/compiler/passes/pass_manager.py b/compiler/passes/pass_manager.py index 32e2feb..d555984 100644 --- a/compiler/passes/pass_manager.py +++ b/compiler/passes/pass_manager.py @@ -5,6 +5,7 @@ from compiler.passes.analyses.call_graph import CallGraph from compiler.passes.analyses.def_use import DefUseChains from compiler.passes.transforms.inline import Inline +from compiler.passes.transforms.loop_unroll import LoopUnroll from compiler.passes.transforms.split_edges import SplitEdges from compiler.passes.transforms.ssa import SSA from shared.bs_exceptions import UnInitializedError @@ -58,4 +59,5 @@ def init_transforms(self): if self.config.inline: self.transforms['inline'] = Inline() self.transforms['split_edges'] = SplitEdges() + self.transforms['loop_unroll'] = LoopUnroll() self.dependencies['transforms'].add_node('split_edges') diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py new file mode 100644 index 0000000..aa23633 --- /dev/null +++ b/compiler/passes/transforms/loop_unroll.py @@ -0,0 +1,101 @@ +from compiler.data_structures import BinaryOps +from compiler.data_structures.program import Program +from compiler.passes.transforms.bs_transform import BSTransform +import networkx as nx + + +class LoopUnroll(BSTransform): + + def __init__(self): + super().__init__("LoopUnravel") + self.log.warn("Hello World") + + #Function: + #1) Assign - Use Cycle to find parent, child, end + #2) Identify - Find Multiplicity in Parent(The number of times we run the loop) + #3) Execute + # ex: while(x < Parent.Multiplicity) + # Child += Child + # x + = 1 + # Child+=End + #) Clean-Up + # Child.incomingEdges += Parent.incoming edges (Loop-through,external to the cycle ofc) + # Remove Parent + # Child.outgoing += End.outgoing ( Loop through ,external to the cycle) + # Remove End + # Just assumes second item is the reverse edge + def unroll(self, program: Program): + for root in program.functions: + self.log.warn(program.functions[root]['graph']) + try: + glist = list(nx.find_cycle(program.functions[root]['graph'])) + except: + self.log.warn("No Cycles Found") + + child = int(glist[1][0]) + parent = glist[1][1] + #root[child] = root[child] + root[child] + #del(root[parent]) + #Remove the jumps from the child to the parent + #Find the multiplier in the parent + #"Multiply" the instruction in the child + # Edge Cases + # 1) variable to constant, variable doesn't change + # 2) variable to variable ,neither change + # 3) variable to constant, wrong direction + ###################################################33 + + # Pops Jump + jump = program.functions[root]['blocks'][child].instructions.pop(2) + BO = program.functions[root]['blocks'][child].instructions.pop(1) + if BinaryOps.SUBTRACT == BO.op : + pass + else: + return + reducer = BO.right + + #Find the constant and find the false-jump + + label = program.functions[root]['blocks'][parent].instructions.pop(1) + #constant = label.right + constant = 8 + jump.jumps = label.false_branch + old = program.functions[root]['blocks'][child].instructions[0] + while constant > 0: + program.functions[root]['blocks'][child].instructions.append(old) + constant -= 1 + program.functions[root]['blocks'][child].instructions.append(jump) + program.functions[root]['blocks'].pop(parent) + + + + + + + # Pops the X Modifer instruction + #Str_Value = " " + program.functions[root]['blocks'][child].instructions.pop(1) + #Gets X Modifer + #value_list = Str_Value.split() + #reducer = value_list[-1] + #self.log.warn(reducer) + + + #self.log.warn(program.functions[root]['blocks'][child]) + + + + for root in program.functions: + for block in program.functions[root]['blocks']: + self.log.warn(program.functions[root]['blocks'][block]) + + + + + + +#Entry Point + def transform(self, program: Program) -> Program: + self.unroll(program) + + return program + From d14ed5719a23c051ecb58fcdad66f87edb333710 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Tue, 18 Jun 2019 15:13:50 -0700 Subject: [PATCH 21/48] Loop Unroll Improvements: Jump, Label --- compiler/passes/transforms/loop_unroll.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index aa23633..5c9754f 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -60,12 +60,15 @@ def unroll(self, program: Program): #constant = label.right constant = 8 jump.jumps = label.false_branch - old = program.functions[root]['blocks'][child].instructions[0] - while constant > 0: - program.functions[root]['blocks'][child].instructions.append(old) + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + while constant > 1: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant -= 1 + #Clean-Up : Pops Parent, adds jump, redoes the labels. program.functions[root]['blocks'][child].instructions.append(jump) program.functions[root]['blocks'].pop(parent) + program.functions[root]['blocks'][child].label = label.true_branch + program.functions[root]['blocks'][child].jumps.pop() @@ -95,6 +98,12 @@ def unroll(self, program: Program): #Entry Point def transform(self, program: Program) -> Program: + for root in program.functions: + for block in program.functions[root]['blocks']: + self.log.warn(program.functions[root]['blocks'][block]) + + + self.unroll(program) return program From 0e8589ce1161b9afcff5dcb543c872130b6e39c4 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Tue, 18 Jun 2019 15:48:50 -0700 Subject: [PATCH 22/48] CHECKPOINT: Basic Loop Unravel Complete. Next Step: Edge Cases, refactor --- compiler/passes/transforms/loop_unroll.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 5c9754f..7e129d4 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -61,6 +61,20 @@ def unroll(self, program: Program): constant = 8 jump.jumps = label.false_branch base_instructions = program.functions[root]['blocks'][child].instructions.copy() + + + #Edge Cases: + # Multiply Oscillate + # DIvide Oscillate + # Multiply to Limit + # Divide to Limit + # Increment to max + # Decrement to Min + + + + + while constant > 1: program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant -= 1 From 1bbc1617a0c1ed8d1eaa4e351d7849d3e8297358 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 19 Jun 2019 13:34:45 -0700 Subject: [PATCH 23/48] Add and Subtract Unrolls working. Jump, Label, Binary OP detection working. --- compiler/passes/transforms/loop_unroll.py | 185 +++++++++++----------- 1 file changed, 96 insertions(+), 89 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 7e129d4..a61de29 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -1,124 +1,131 @@ -from compiler.data_structures import BinaryOps +from compiler.data_structures import * from compiler.data_structures.program import Program from compiler.passes.transforms.bs_transform import BSTransform import networkx as nx + class LoopUnroll(BSTransform): def __init__(self): super().__init__("LoopUnravel") - self.log.warn("Hello World") - - #Function: - #1) Assign - Use Cycle to find parent, child, end - #2) Identify - Find Multiplicity in Parent(The number of times we run the loop) - #3) Execute - # ex: while(x < Parent.Multiplicity) - # Child += Child - # x + = 1 - # Child+=End - #) Clean-Up - # Child.incomingEdges += Parent.incoming edges (Loop-through,external to the cycle ofc) - # Remove Parent - # Child.outgoing += End.outgoing ( Loop through ,external to the cycle) - # Remove End - # Just assumes second item is the reverse edge - def unroll(self, program: Program): + self.log.warn("Starting Loop Unrolling.....") + + + def unroll(self, program: Program) -> Program: + global jump for root in program.functions: - self.log.warn(program.functions[root]['graph']) try: glist = list(nx.find_cycle(program.functions[root]['graph'])) except: - self.log.warn("No Cycles Found") - - child = int(glist[1][0]) - parent = glist[1][1] - #root[child] = root[child] + root[child] - #del(root[parent]) - #Remove the jumps from the child to the parent - #Find the multiplier in the parent - #"Multiply" the instruction in the child - # Edge Cases - # 1) variable to constant, variable doesn't change - # 2) variable to variable ,neither change - # 3) variable to constant, wrong direction - ###################################################33 - - # Pops Jump - jump = program.functions[root]['blocks'][child].instructions.pop(2) - BO = program.functions[root]['blocks'][child].instructions.pop(1) - if BinaryOps.SUBTRACT == BO.op : - pass + self.log.warn("No Loops Found. No need to unroll") + return program #No Cycles to unroll! + + + child = glist[1][0] + parent =glist[1][1] + + # Loop Unroll Algorithm + # Find Variables in Block 1 + # Detect Usage in Block 2 (Instruction with a BinaryOP on variable) + # Detect if BinaryOp follows protocol + # If so, unroll loop nicely + + # TODO : Get Left variable on jump condition + # TODO: Better Jump Detect Algorithm, find variable from parent in child + + # This label is the conditional on the parent.... + # We loop through all conditionals, find the last (that will be the last argument anyway) + # Search that conditional for a variable, store the variable as an object + #Remove the last condition (loop header) + + ##IDENTIFY + #PARENT MODIFICATIONS + #label = None + for items in program.functions[root]['blocks'][parent].instructions: + if type(items) == Conditional: + self.log.warn("Success") + label = program.functions[root]['blocks'][parent].instructions.pop( + program.functions[root]['blocks'][parent].instructions.index(items)) + l_left = label.left + l_right = label.right + else: + self.log.warn(type(items)) + # Remove Jumps + self.log.warn(label ) + #CHILD MODIFICATIONS + jump = program.functions[root]['blocks'][child].instructions.pop(-1) + for items2 in program.functions[root]['blocks'][child].instructions: + + if type(items2) == BinaryOp: + self.log.warn("Success") + BO = program.functions[root]['blocks'][child].instructions.pop( + program.functions[root]['blocks'][child].instructions.index(items2)) + else: + self.log.warn(items2) + self.log.warn(type(items2)) + # self.log.warn(jump + "Henlo" ) + self.log.warn(BO) + + #EXECUTE + if BinaryOps.SUBTRACT == BO.op: + + reducer = BO.right + + #Find the constant and find the false-jump + + # TODO: Better Jump Condition Detect + #constant = label.right + constant = 8 + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + while constant > 1: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant -= 1 + elif BinaryOps.ADD == BO.op: + reducer = BO.right + + # Find the constant and find the false-jump + + # TODO: Better Jump Condition Detect + # TODO: FIX NUMBER CITIZENSHIP + # constant = label.right + constant = 1 + + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + while constant < 7: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant += 1 + elif BinaryOps.MULTIPLE == BO.op: + pass + elif BinaryOps.DIVIDE == BO.op: + pass else: - return - reducer = BO.right - - #Find the constant and find the false-jump + self.log.warn("Control Logic Detected... Aborting Unroll") - label = program.functions[root]['blocks'][parent].instructions.pop(1) - #constant = label.right - constant = 8 + #CLEANUP: Pops Parent, adds jump, redoes the labels. jump.jumps = label.false_branch - base_instructions = program.functions[root]['blocks'][child].instructions.copy() - - - #Edge Cases: - # Multiply Oscillate - # DIvide Oscillate - # Multiply to Limit - # Divide to Limit - # Increment to max - # Decrement to Min - - - - - - while constant > 1: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant -= 1 - #Clean-Up : Pops Parent, adds jump, redoes the labels. program.functions[root]['blocks'][child].instructions.append(jump) program.functions[root]['blocks'].pop(parent) program.functions[root]['blocks'][child].label = label.true_branch program.functions[root]['blocks'][child].jumps.pop() - - - - - # Pops the X Modifer instruction - #Str_Value = " " + program.functions[root]['blocks'][child].instructions.pop(1) - #Gets X Modifer - #value_list = Str_Value.split() - #reducer = value_list[-1] - #self.log.warn(reducer) - - - #self.log.warn(program.functions[root]['blocks'][child]) - - - + #Test code showing program post unroll for root in program.functions: for block in program.functions[root]['blocks']: self.log.warn(program.functions[root]['blocks'][block]) - - + self.log.warn("Loop Unrolling Completed") + return program #Entry Point def transform(self, program: Program) -> Program: + #Test Print to show pre-unroll for root in program.functions: for block in program.functions[root]['blocks']: self.log.warn(program.functions[root]['blocks'][block]) - - - - self.unroll(program) - - return program + #Test function + return self.unroll(program) From 6d73552f0982a42fc4e6118eecf2ffd312809414 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 19 Jun 2019 16:22:01 -0700 Subject: [PATCH 24/48] Pre-Number Promotion final loop unroll --- compiler/passes/transforms/loop_unroll.py | 37 ++++++++++++----------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index a61de29..c20f542 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -20,10 +20,8 @@ def unroll(self, program: Program) -> Program: except: self.log.warn("No Loops Found. No need to unroll") return program #No Cycles to unroll! - - child = glist[1][0] - parent =glist[1][1] + parent = glist[1][1] # Loop Unroll Algorithm # Find Variables in Block 1 @@ -31,7 +29,7 @@ def unroll(self, program: Program) -> Program: # Detect if BinaryOp follows protocol # If so, unroll loop nicely - # TODO : Get Left variable on jump condition + # TODO : Get Left variable on jump condition jump.jumps = label.false_branch # TODO: Better Jump Detect Algorithm, find variable from parent in child # This label is the conditional on the parent.... @@ -39,9 +37,18 @@ def unroll(self, program: Program) -> Program: # Search that conditional for a variable, store the variable as an object #Remove the last condition (loop header) + + # Var Detect Algo + # Check if any match of the label condition + # matches any leaf in BinaryOps in the stack + # + ##IDENTIFY #PARENT MODIFICATIONS #label = None + label = None + BO = None + jump = None for items in program.functions[root]['blocks'][parent].instructions: if type(items) == Conditional: self.log.warn("Success") @@ -50,7 +57,7 @@ def unroll(self, program: Program) -> Program: l_left = label.left l_right = label.right else: - self.log.warn(type(items)) + pass # Remove Jumps self.log.warn(label ) #CHILD MODIFICATIONS @@ -59,23 +66,19 @@ def unroll(self, program: Program) -> Program: if type(items2) == BinaryOp: self.log.warn("Success") + #TODO: Better BinaryOp Chec + # 4 Cases: BO = program.functions[root]['blocks'][child].instructions.pop( program.functions[root]['blocks'][child].instructions.index(items2)) else: - self.log.warn(items2) - self.log.warn(type(items2)) + pass # self.log.warn(jump + "Henlo" ) - self.log.warn(BO) - + if jump is None or label is None or BO is None: + self.log.warn("Bad or Infinite Loop Detected... aborting unroll") + return program #EXECUTE if BinaryOps.SUBTRACT == BO.op: - - reducer = BO.right - - #Find the constant and find the false-jump - - # TODO: Better Jump Condition Detect - #constant = label.right + #constant = BO.right constant = 8 base_instructions = program.functions[root]['blocks'][child].instructions.copy() while constant > 1: @@ -100,7 +103,7 @@ def unroll(self, program: Program) -> Program: elif BinaryOps.DIVIDE == BO.op: pass else: - self.log.warn("Control Logic Detected... Aborting Unroll") + pass #CLEANUP: Pops Parent, adds jump, redoes the labels. jump.jumps = label.false_branch From 5b4c29ca4e1c7422563e844774c9d2fd51bdf72e Mon Sep 17 00:00:00 2001 From: startwarfields Date: Thu, 20 Jun 2019 15:44:16 -0700 Subject: [PATCH 25/48] Final Pre-Math Implementation --- compiler/passes/transforms/loop_unroll.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index c20f542..baca790 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -49,6 +49,12 @@ def unroll(self, program: Program) -> Program: label = None BO = None jump = None + + #remove end char from each item in set. + #compare to binaryOp item + variables = program.functions[root]['blocks'][parent].uses + + self.log.warn(variables) for items in program.functions[root]['blocks'][parent].instructions: if type(items) == Conditional: self.log.warn("Success") From bdd1f8f3113810cb6f3ea35062e31ec5c1dcd3fc Mon Sep 17 00:00:00 2001 From: startwarfields Date: Fri, 21 Jun 2019 12:14:07 -0700 Subject: [PATCH 26/48] Unnested Loop unrolling partially working --- compiler/passes/transforms/loop_unroll.py | 269 +++++++++++----------- 1 file changed, 137 insertions(+), 132 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index baca790..d226d9d 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -4,137 +4,142 @@ import networkx as nx - class LoopUnroll(BSTransform): - def __init__(self): - super().__init__("LoopUnravel") - self.log.warn("Starting Loop Unrolling.....") - - - def unroll(self, program: Program) -> Program: - global jump - for root in program.functions: - try: - glist = list(nx.find_cycle(program.functions[root]['graph'])) - except: - self.log.warn("No Loops Found. No need to unroll") - return program #No Cycles to unroll! - child = glist[1][0] - parent = glist[1][1] - - # Loop Unroll Algorithm - # Find Variables in Block 1 - # Detect Usage in Block 2 (Instruction with a BinaryOP on variable) - # Detect if BinaryOp follows protocol - # If so, unroll loop nicely - - # TODO : Get Left variable on jump condition jump.jumps = label.false_branch - # TODO: Better Jump Detect Algorithm, find variable from parent in child - - # This label is the conditional on the parent.... - # We loop through all conditionals, find the last (that will be the last argument anyway) - # Search that conditional for a variable, store the variable as an object - #Remove the last condition (loop header) - - - # Var Detect Algo - # Check if any match of the label condition - # matches any leaf in BinaryOps in the stack - # - - ##IDENTIFY - #PARENT MODIFICATIONS - #label = None - label = None - BO = None - jump = None - - #remove end char from each item in set. - #compare to binaryOp item - variables = program.functions[root]['blocks'][parent].uses - - self.log.warn(variables) - for items in program.functions[root]['blocks'][parent].instructions: - if type(items) == Conditional: - self.log.warn("Success") - label = program.functions[root]['blocks'][parent].instructions.pop( - program.functions[root]['blocks'][parent].instructions.index(items)) - l_left = label.left - l_right = label.right - else: - pass - # Remove Jumps - self.log.warn(label ) - #CHILD MODIFICATIONS - jump = program.functions[root]['blocks'][child].instructions.pop(-1) - for items2 in program.functions[root]['blocks'][child].instructions: - - if type(items2) == BinaryOp: - self.log.warn("Success") - #TODO: Better BinaryOp Chec - # 4 Cases: - BO = program.functions[root]['blocks'][child].instructions.pop( - program.functions[root]['blocks'][child].instructions.index(items2)) - else: - pass - # self.log.warn(jump + "Henlo" ) - if jump is None or label is None or BO is None: - self.log.warn("Bad or Infinite Loop Detected... aborting unroll") - return program - #EXECUTE - if BinaryOps.SUBTRACT == BO.op: - #constant = BO.right - constant = 8 - base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while constant > 1: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant -= 1 - elif BinaryOps.ADD == BO.op: - reducer = BO.right - - # Find the constant and find the false-jump - - # TODO: Better Jump Condition Detect - # TODO: FIX NUMBER CITIZENSHIP - # constant = label.right - constant = 1 - - base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while constant < 7: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant += 1 - elif BinaryOps.MULTIPLE == BO.op: - pass - elif BinaryOps.DIVIDE == BO.op: - pass - else: - pass - - #CLEANUP: Pops Parent, adds jump, redoes the labels. - jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.append(jump) - program.functions[root]['blocks'].pop(parent) - program.functions[root]['blocks'][child].label = label.true_branch - program.functions[root]['blocks'][child].jumps.pop() - - - #Test code showing program post unroll - for root in program.functions: - for block in program.functions[root]['blocks']: - self.log.warn(program.functions[root]['blocks'][block]) - self.log.warn("Loop Unrolling Completed") - return program - - - - -#Entry Point - def transform(self, program: Program) -> Program: - #Test Print to show pre-unroll - for root in program.functions: - for block in program.functions[root]['blocks']: - self.log.warn(program.functions[root]['blocks'][block]) - #Test function - return self.unroll(program) - + def __init__(self): + super().__init__("LoopUnravel") + self.log.warn("Starting Loop Unrolling.....") + + def unroll(self, program: Program) -> Program: + global jump + for root in program.functions: + try: + glist = list(nx.find_cycle(program.functions[root]['graph'])) + except: + self.log.warn("No Loops Found. No need to unroll") + return program # No Cycles to unroll! + child = glist[1][0] + parent = glist[1][1] + + # Loop Unroll Algorithm + # Find Variables in Block 1 + # Detect Usage in Block 2 (Instruction with a BinaryOP on variable) + # Detect if BinaryOp follows protocol + # If so, unroll loop nicely + + # TODO : Get Left variable on jump condition jump.jumps = label.false_branch + # TODO: Better Jump Detect Algorithm, find variable from parent in child + + # This label is the conditional on the parent.... + # We loop through all conditionals, find the last (that will be the last argument anyway) + # Search that conditional for a variable, store the variable as an object + # Remove the last condition (loop header) + + # Expression check storage variable is + + ##IDENTIFY + # PARENT MODIFICATIONS + # label = None + label = None + BO = None + jump = None + + # remove end char from each item in set. + # compare to binaryOp item + variables = program.functions[root]['blocks'][parent].uses + #check to se + + self.log.warn(variables) + for items in program.functions[root]['blocks'][parent].instructions: + if type(items) == Conditional: + self.log.warn("Success") + label = program.functions[root]['blocks'][parent].instructions.pop( + program.functions[root]['blocks'][parent].instructions.index(items)) + l_left = label.left + l_right = label.right + else: + pass + # Remove Jumps + self.log.warn(l_left) + # CHILD MODIFICATIONS + jump = program.functions[root]['blocks'][child].instructions.pop(-1) + BadLoop = True + for items2 in program.functions[root]['blocks'][child].instructions: + + if type(items2) == BinaryOp: + self.log.warn("Success") + # TODO: Better BinaryOp Chec + # 4 Cases: + BO = program.functions[root]['blocks'][child].instructions.pop( + program.functions[root]['blocks'][child].instructions.index(items2)) + if BO.defs.name[:-1] == l_left.name: + BadLoop = False + elif BO.defs.name[:-1] == l_right.name: + BadLoop = False + + else: + pass + # self.log.warn(jump + "Henlo" ) + if jump is None or label is None or BO is None: + self.log.warn("Bad or Infinite Loop Detected... aborting unroll") + return program + + + if(BadLoop): + self.log.warn("Infinite or Bad Loop Detected....exiting Loop Unroll") + return Program + + + + # check variable in l_left or l_right is in bo_defs + # EXECUTE + if BinaryOps.SUBTRACT == BO.op: + # constant = BO.right + constant = 8 + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + while constant > 1: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant -= 1 + elif BinaryOps.ADD == BO.op: + reducer = BO.right + + # Find the constant and find the false-jump + + # TODO: Better Jump Condition Detect + # TODO: FIX NUMBER CITIZENSHIP + # constant = label.right + constant = 1 + + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + while constant < 7: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant += 1 + elif BinaryOps.MULTIPLE == BO.op: + pass + elif BinaryOps.DIVIDE == BO.op: + pass + else: + pass + + # CLEANUP: Pops Parent, adds jump, redoes the labels. + jump.jumps = label.false_branch + program.functions[root]['blocks'][child].instructions.append(jump) + program.functions[root]['blocks'].pop(parent) + program.functions[root]['blocks'][child].label = label.true_branch + program.functions[root]['blocks'][child].jumps.pop() + + # Test code showing program post unroll + for root in program.functions: + for block in program.functions[root]['blocks']: + self.log.warn(program.functions[root]['blocks'][block]) + self.log.warn("Loop Unrolling Completed") + return program + + # Entry Point + def transform(self, program: Program) -> Program: + # Test Print to show pre-unroll + for root in program.functions: + for block in program.functions[root]['blocks']: + self.log.warn(program.functions[root]['blocks'][block]) + # Test function + return self.unroll(program) From 5b4cd07673ac831f2f9f49cb4fa5ba24e56bcecb Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 24 Jun 2019 13:44:46 -0700 Subject: [PATCH 27/48] Better Loop Algorithm. Using Simple_Cycles to correctly attempt each loop in every function once. Stil WIP --- compiler/passes/transforms/loop_unroll.py | 219 ++++++++++------------ 1 file changed, 99 insertions(+), 120 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index d226d9d..aaffd05 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -13,133 +13,112 @@ def __init__(self): def unroll(self, program: Program) -> Program: global jump for root in program.functions: - try: - glist = list(nx.find_cycle(program.functions[root]['graph'])) - except: - self.log.warn("No Loops Found. No need to unroll") - return program # No Cycles to unroll! - child = glist[1][0] - parent = glist[1][1] - - # Loop Unroll Algorithm - # Find Variables in Block 1 - # Detect Usage in Block 2 (Instruction with a BinaryOP on variable) - # Detect if BinaryOp follows protocol - # If so, unroll loop nicely - - # TODO : Get Left variable on jump condition jump.jumps = label.false_branch - # TODO: Better Jump Detect Algorithm, find variable from parent in child - - # This label is the conditional on the parent.... - # We loop through all conditionals, find the last (that will be the last argument anyway) - # Search that conditional for a variable, store the variable as an object - # Remove the last condition (loop header) - - # Expression check storage variable is - - ##IDENTIFY - # PARENT MODIFICATIONS - # label = None - label = None - BO = None - jump = None - - # remove end char from each item in set. - # compare to binaryOp item - variables = program.functions[root]['blocks'][parent].uses - #check to se - - self.log.warn(variables) - for items in program.functions[root]['blocks'][parent].instructions: - if type(items) == Conditional: - self.log.warn("Success") - label = program.functions[root]['blocks'][parent].instructions.pop( - program.functions[root]['blocks'][parent].instructions.index(items)) - l_left = label.left - l_right = label.right - else: - pass - # Remove Jumps - self.log.warn(l_left) - # CHILD MODIFICATIONS - jump = program.functions[root]['blocks'][child].instructions.pop(-1) - BadLoop = True - for items2 in program.functions[root]['blocks'][child].instructions: - - if type(items2) == BinaryOp: - self.log.warn("Success") - # TODO: Better BinaryOp Chec - # 4 Cases: - BO = program.functions[root]['blocks'][child].instructions.pop( - program.functions[root]['blocks'][child].instructions.index(items2)) - if BO.defs.name[:-1] == l_left.name: - BadLoop = False - elif BO.defs.name[:-1] == l_right.name: - BadLoop = False - - else: - pass - # self.log.warn(jump + "Henlo" ) - if jump is None or label is None or BO is None: - self.log.warn("Bad or Infinite Loop Detected... aborting unroll") - return program - - - if(BadLoop): - self.log.warn("Infinite or Bad Loop Detected....exiting Loop Unroll") - return Program - - - - # check variable in l_left or l_right is in bo_defs - # EXECUTE - if BinaryOps.SUBTRACT == BO.op: - # constant = BO.right - constant = 8 - base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while constant > 1: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant -= 1 - elif BinaryOps.ADD == BO.op: - reducer = BO.right - - # Find the constant and find the false-jump - - # TODO: Better Jump Condition Detect - # TODO: FIX NUMBER CITIZENSHIP - # constant = label.right - constant = 1 - - base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while constant < 7: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant += 1 - elif BinaryOps.MULTIPLE == BO.op: - pass - elif BinaryOps.DIVIDE == BO.op: - pass - else: - pass - - # CLEANUP: Pops Parent, adds jump, redoes the labels. - jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.append(jump) - program.functions[root]['blocks'].pop(parent) - program.functions[root]['blocks'][child].label = label.true_branch - program.functions[root]['blocks'][child].jumps.pop() - + #try: + glist = list(nx.find_cycle(program.functions[root]['graph'])) + tlist = list(nx.simple_cycles(program.functions[root]['graph'])) + for item in tlist: + child = item[1] + parent = item[0] + self.log.warn(child) + label = None + BO = None + jump = None + + # remove end char from each item in set. + # compare to binaryOp item + variables = program.functions[root]['blocks'][parent].uses + labels = [] + #check to se + + self.log.warn(variables) + for items in program.functions[root]['blocks'][parent].instructions: + if type(items) == Conditional: + self.log.warn("Success") + label = program.functions[root]['blocks'][parent].instructions.pop( + program.functions[root]['blocks'][parent].instructions.index(items)) + labels.append(label) + l_left = label.left + l_right = label.right + else: + pass + # Remove Jumps + self.log.warn(labels) + # CHILD MODIFICATIONS + jump = program.functions[root]['blocks'][child].instructions.pop(-1) + BadLoop = True + for items2 in program.functions[root]['blocks'][child].instructions: + + if type(items2) == BinaryOp: + self.log.warn("Success") + # TODO: Better BinaryOp Chec + # 4 Cases: + BO = program.functions[root]['blocks'][child].instructions.pop( + program.functions[root]['blocks'][child].instructions.index(items2)) + if BO.defs.name[:-1] == l_left.name: + BadLoop = False + elif BO.defs.name[:-1] == l_right.name: + BadLoop = False + + else: + pass + # self.log.warn(jump + "Henlo" ) + if jump is None or label is None or BO is None or BadLoop: + self.log.warn(BadLoop) + self.log.warn("Bad or Infinite Loop Detected... aborting unroll") + continue + + + + # check variable in l_left or l_right is in bo_defs + # EXECUTE + if BinaryOps.SUBTRACT == BO.op: + # constant = BO.right + constant = 8 + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + while constant > 1: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant -= 1 + elif BinaryOps.ADD == BO.op: + reducer = BO.right + + # Find the constant and find the false-jump + + # TODO: Better Jump Condition Detect + # TODO: FIX NUMBER CITIZENSHIP + # constant = label.right + constant = 1 + + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + while constant < 7: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant += 1 + elif BinaryOps.MULTIPLE == BO.op: + pass + elif BinaryOps.DIVIDE == BO.op: + pass + else: + pass + + # CLEANUP: Pops Parent, adds jump, redoes the labels. + jump.jumps = label.false_branch + program.functions[root]['blocks'][child].instructions.append(jump) + program.functions[root]['blocks'].pop(parent) + program.functions[root]['blocks'][child].label = label.true_branch + program.functions[root]['blocks'][child].jumps.pop() + + #except: + self.log.warn("No Loops Found in Function") # Test code showing program post unroll - for root in program.functions: - for block in program.functions[root]['blocks']: - self.log.warn(program.functions[root]['blocks'][block]) - self.log.warn("Loop Unrolling Completed") + + return program # Entry Point def transform(self, program: Program) -> Program: - # Test Print to show pre-unroll for root in program.functions: for block in program.functions[root]['blocks']: self.log.warn(program.functions[root]['blocks'][block]) + self.log.warn("Loop Unrolling Completed") + # Test Print to show pre-unroll # Test function return self.unroll(program) From b72ead0397d6f005ec3e7236c21df4450e1517b1 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Tue, 25 Jun 2019 13:45:39 -0700 Subject: [PATCH 28/48] Better Add Loop Type unrolling --- compiler/passes/transforms/loop_unroll.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index aaffd05..faa796a 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -28,6 +28,8 @@ def unroll(self, program: Program) -> Program: # compare to binaryOp item variables = program.functions[root]['blocks'][parent].uses labels = [] + + #check to se self.log.warn(variables) @@ -72,7 +74,7 @@ def unroll(self, program: Program) -> Program: # check variable in l_left or l_right is in bo_defs # EXECUTE if BinaryOps.SUBTRACT == BO.op: - # constant = BO.right + constant = 8 base_instructions = program.functions[root]['blocks'][child].instructions.copy() while constant > 1: @@ -86,12 +88,13 @@ def unroll(self, program: Program) -> Program: # TODO: Better Jump Condition Detect # TODO: FIX NUMBER CITIZENSHIP # constant = label.right - constant = 1 + constant = 0 + self.log.warn(BO.right) base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while constant < 7: + while constant < label.right.value: program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant += 1 + constant += int(BO.right) elif BinaryOps.MULTIPLE == BO.op: pass elif BinaryOps.DIVIDE == BO.op: @@ -108,6 +111,10 @@ def unroll(self, program: Program) -> Program: #except: self.log.warn("No Loops Found in Function") + for root in program.functions: + for block in program.functions[root]['blocks']: + self.log.warn(program.functions[root]['blocks'][block]) + self.log.warn("Loop Unrolling Completed") # Test code showing program post unroll From 7707a487632babd2099c78fa4afbc5f644d2ea10 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Tue, 25 Jun 2019 14:24:31 -0700 Subject: [PATCH 29/48] Better handling of relops for single add use case --- compiler/passes/transforms/loop_unroll.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index faa796a..880176f 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -92,9 +92,20 @@ def unroll(self, program: Program) -> Program: self.log.warn(BO.right) base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while constant < label.right.value: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant += int(BO.right) + keep_looping = True + + while keep_looping: + if label.relop.value == 4: + + if constant < label.right.value - 1: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant += int(BO.right) + else: + keep_looping = False + else: + keep_looping = False + + elif BinaryOps.MULTIPLE == BO.op: pass elif BinaryOps.DIVIDE == BO.op: From d78194b49ae72cf3ab5a2cfe9b5e2364c527e521 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Tue, 25 Jun 2019 14:53:41 -0700 Subject: [PATCH 30/48] Added simple multiple loop unroll. --- compiler/passes/transforms/loop_unroll.py | 44 ++++++++++++++--------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 880176f..cde751c 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -69,44 +69,56 @@ def unroll(self, program: Program) -> Program: self.log.warn("Bad or Infinite Loop Detected... aborting unroll") continue - - + keep_looping = True # check variable in l_left or l_right is in bo_defs # EXECUTE if BinaryOps.SUBTRACT == BO.op: - constant = 8 base_instructions = program.functions[root]['blocks'][child].instructions.copy() while constant > 1: program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant -= 1 elif BinaryOps.ADD == BO.op: - reducer = BO.right - - # Find the constant and find the false-jump - - # TODO: Better Jump Condition Detect - # TODO: FIX NUMBER CITIZENSHIP - # constant = label.right - constant = 0 - self.log.warn(BO.right) - + constant = 1 base_instructions = program.functions[root]['blocks'][child].instructions.copy() - keep_looping = True + while keep_looping: if label.relop.value == 4: - if constant < label.right.value - 1: + if constant < label.right.value: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant += int(BO.right) + else: + keep_looping = False + elif label.relop.value == 0: + if constant == label.right.value: program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant += int(BO.right) else: keep_looping = False else: keep_looping = False + elif BinaryOps.MULTIPLE == BO.op: + constant = 1 + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + while keep_looping: + if label.relop.value == 4: - elif BinaryOps.MULTIPLE == BO.op: + if constant < label.right.value : + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant *= int(BO.right) + else: + keep_looping = False + elif label.relop.value == 0: + if constant == label.right.value: + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant *= int(BO.right) + else: + keep_looping = False + else: + keep_looping = False pass elif BinaryOps.DIVIDE == BO.op: pass From c5ba18efaf3f7aa26499376626603509dae93ca4 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 10:27:38 -0700 Subject: [PATCH 31/48] Refactored Execute Phase of Loop Unrolling, Next Steps: Cleaner Identify, and Induction Proof for Finite Loops --- compiler/passes/transforms/loop_unroll.py | 209 +++++++++------------- 1 file changed, 87 insertions(+), 122 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index cde751c..d9b96bb 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -10,137 +10,102 @@ def __init__(self): super().__init__("LoopUnravel") self.log.warn("Starting Loop Unrolling.....") + def getCondition(self, RO, x, y): + if RO == RelationalOps.EQUALITY: + return True if x == y else False + elif RO == RelationalOps.NE: + return True if x != y else False + elif RO == RelationalOps.LT: + return True if x < y else False + elif RO == RelationalOps.LTE: + return True if x <= y else False + elif RO == RelationalOps.GT: + return True if x > y else False + elif RO == RelationalOps.GTE: + return True if x >= y else False + else: + return False + + def calculateNewValue(self, BO: BinaryOp, x, y): + if BO.op == BinaryOps.SUBTRACT: + x = x - y + elif BO.op == BinaryOps.ADD: + x = x + y + elif BO.op == BinaryOps.MULTIPLE: + x = x * y + elif BO.op == BinaryOps.DIVIDE: + x = x / y + elif BO.op == BinaryOps.AND: + x = x & y + elif BO.op == BinaryOps.OR: + x = x | y + return x + + # TODO: Use "Induction" to determine finite loops + def inductionProof(self, BO, RO, x, y): + return False + def unroll(self, program: Program) -> Program: global jump for root in program.functions: - #try: - glist = list(nx.find_cycle(program.functions[root]['graph'])) - tlist = list(nx.simple_cycles(program.functions[root]['graph'])) - for item in tlist: - child = item[1] - parent = item[0] - self.log.warn(child) - label = None - BO = None - jump = None - - # remove end char from each item in set. - # compare to binaryOp item - variables = program.functions[root]['blocks'][parent].uses - labels = [] - - - #check to se - - self.log.warn(variables) - for items in program.functions[root]['blocks'][parent].instructions: - if type(items) == Conditional: - self.log.warn("Success") - label = program.functions[root]['blocks'][parent].instructions.pop( - program.functions[root]['blocks'][parent].instructions.index(items)) - labels.append(label) - l_left = label.left - l_right = label.right - else: - pass - # Remove Jumps - self.log.warn(labels) - # CHILD MODIFICATIONS - jump = program.functions[root]['blocks'][child].instructions.pop(-1) - BadLoop = True - for items2 in program.functions[root]['blocks'][child].instructions: - - if type(items2) == BinaryOp: - self.log.warn("Success") - # TODO: Better BinaryOp Chec - # 4 Cases: - BO = program.functions[root]['blocks'][child].instructions.pop( - program.functions[root]['blocks'][child].instructions.index(items2)) - if BO.defs.name[:-1] == l_left.name: - BadLoop = False - elif BO.defs.name[:-1] == l_right.name: - BadLoop = False - - else: - pass - # self.log.warn(jump + "Henlo" ) - if jump is None or label is None or BO is None or BadLoop: - self.log.warn(BadLoop) - self.log.warn("Bad or Infinite Loop Detected... aborting unroll") - continue - - keep_looping = True - # check variable in l_left or l_right is in bo_defs - # EXECUTE - if BinaryOps.SUBTRACT == BO.op: - constant = 8 - base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while constant > 1: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant -= 1 - elif BinaryOps.ADD == BO.op: - constant = 1 - base_instructions = program.functions[root]['blocks'][child].instructions.copy() + tlist = list(nx.simple_cycles(program.functions[root]['graph'])) + for item in tlist: + child = item[1] + parent = item[0] + label = None + binary_operation = None + jump = None + labels = [] + # IDENTIFY + # TODO: Better Identification of Conditionals + # Parent Instructions + for p_instructions in program.functions[root]['blocks'][parent].instructions: + if type(p_instructions) == Conditional: + self.log.warn("Success") + label = program.functions[root]['blocks'][parent].instructions.pop( + program.functions[root]['blocks'][parent].instructions.index(p_instructions)) + labels.append(label) + l_left = label.left + l_right = label.right + else: + pass + # Child Instructions + jump = program.functions[root]['blocks'][child].instructions.pop(-1) + badloop = True + for c_instructions in program.functions[root]['blocks'][child].instructions: + if type(c_instructions) == BinaryOp: + self.log.warn("Success") + # TODO: Better BinaryOp Chec + # 4 Cases: + binary_operation = program.functions[root]['blocks'][child].instructions.pop( + program.functions[root]['blocks'][child].instructions.index(c_instructions)) + if binary_operation.defs.name[:-1] == l_left.name: + badloop = False + elif binary_operation.defs.name[:-1] == l_right.name: + badloop = False + else: + pass + if jump is None or label is None or binary_operation is None or badloop: + self.log.warn("Bad or Infinite Loop Detected... aborting unroll") + continue + # EXECUTE + constant = 1 + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + while self.getCondition(label.relop.value, constant, label.right.value): + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant = self.calculateNewValue(binary_operation, constant, int(binary_operation.right)) + # CLEANUP: Pops Parent, adds jump, redoes the labels. + jump.jumps = label.false_branch + program.functions[root]['blocks'][child].instructions.append(jump) + program.functions[root]['blocks'].pop(parent) + program.functions[root]['blocks'][child].label = label.true_branch + program.functions[root]['blocks'][child].jumps.pop() - - while keep_looping: - if label.relop.value == 4: - - if constant < label.right.value: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant += int(BO.right) - else: - keep_looping = False - elif label.relop.value == 0: - if constant == label.right.value: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant += int(BO.right) - else: - keep_looping = False - else: - keep_looping = False - elif BinaryOps.MULTIPLE == BO.op: - constant = 1 - base_instructions = program.functions[root]['blocks'][child].instructions.copy() - - while keep_looping: - if label.relop.value == 4: - - if constant < label.right.value : - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant *= int(BO.right) - else: - keep_looping = False - elif label.relop.value == 0: - if constant == label.right.value: - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant *= int(BO.right) - else: - keep_looping = False - else: - keep_looping = False - pass - elif BinaryOps.DIVIDE == BO.op: - pass - else: - pass - - # CLEANUP: Pops Parent, adds jump, redoes the labels. - jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.append(jump) - program.functions[root]['blocks'].pop(parent) - program.functions[root]['blocks'][child].label = label.true_branch - program.functions[root]['blocks'][child].jumps.pop() - - #except: - self.log.warn("No Loops Found in Function") for root in program.functions: for block in program.functions[root]['blocks']: self.log.warn(program.functions[root]['blocks'][block]) self.log.warn("Loop Unrolling Completed") # Test code showing program post unroll - - return program # Entry Point From cb45a540390605c93e133347c6e4a053967dbce6 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 11:05:19 -0700 Subject: [PATCH 32/48] Induction Method added to determine if loop is finite --- compiler/passes/transforms/loop_unroll.py | 25 ++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index d9b96bb..f1c31d6 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -10,7 +10,7 @@ def __init__(self): super().__init__("LoopUnravel") self.log.warn("Starting Loop Unrolling.....") - def getCondition(self, RO, x, y): + def loop_condition(self, RO, x, y): if RO == RelationalOps.EQUALITY: return True if x == y else False elif RO == RelationalOps.NE: @@ -26,7 +26,7 @@ def getCondition(self, RO, x, y): else: return False - def calculateNewValue(self, BO: BinaryOp, x, y): + def reevaluate(self, BO: BinaryOp, x, y): if BO.op == BinaryOps.SUBTRACT: x = x - y elif BO.op == BinaryOps.ADD: @@ -42,8 +42,15 @@ def calculateNewValue(self, BO: BinaryOp, x, y): return x # TODO: Use "Induction" to determine finite loops - def inductionProof(self, BO, RO, x, y): - return False + def finite_loop(self, bin_op, x, y, z, inductive_step=True): + k = self.reevaluate(bin_op, x, y) + k_delta = k - z + zx_delta = x - z + zk_delta = abs(zx_delta) - abs(k_delta) + if inductive_step : i_step = self.finite_loop(bin_op, k, y, z, False) + else: i_step = True + + return True if zk_delta > 0 and i_step else False def unroll(self, program: Program) -> Program: global jump @@ -75,7 +82,8 @@ def unroll(self, program: Program) -> Program: for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: self.log.warn("Success") - # TODO: Better BinaryOp Chec + # TODO: Better Binar + #IDENTyOp Chec # 4 Cases: binary_operation = program.functions[root]['blocks'][child].instructions.pop( program.functions[root]['blocks'][child].instructions.index(c_instructions)) @@ -89,11 +97,14 @@ def unroll(self, program: Program) -> Program: self.log.warn("Bad or Infinite Loop Detected... aborting unroll") continue # EXECUTE + # Warning 0: This Code Works assuming the right is the constant + # Warning 1: This Code is not fully functional: it cannot find the original x value constant = 1 base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while self.getCondition(label.relop.value, constant, label.right.value): + while self.finite_loop(binary_operation,constant,int(binary_operation.right),label.right.value) \ + and self.loop_condition(label.relop.value, constant, label.right.value): program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant = self.calculateNewValue(binary_operation, constant, int(binary_operation.right)) + constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) # CLEANUP: Pops Parent, adds jump, redoes the labels. jump.jumps = label.false_branch program.functions[root]['blocks'][child].instructions.append(jump) From 51a9ff11dc8343fe9477a8fe8ab45615d17c0ba6 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 11:27:52 -0700 Subject: [PATCH 33/48] Loop Unroll correctly resets the instructions of an unrollable loop --- compiler/passes/transforms/loop_unroll.py | 28 ++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index f1c31d6..82b8db1 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -2,6 +2,7 @@ from compiler.data_structures.program import Program from compiler.passes.transforms.bs_transform import BSTransform import networkx as nx +import copy class LoopUnroll(BSTransform): @@ -47,7 +48,7 @@ def finite_loop(self, bin_op, x, y, z, inductive_step=True): k_delta = k - z zx_delta = x - z zk_delta = abs(zx_delta) - abs(k_delta) - if inductive_step : i_step = self.finite_loop(bin_op, k, y, z, False) + if inductive_step: i_step = self.finite_loop(bin_op, k, y, z, False) else: i_step = True return True if zk_delta > 0 and i_step else False @@ -59,6 +60,9 @@ def unroll(self, program: Program) -> Program: for item in tlist: child = item[1] parent = item[0] + + pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) + pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) label = None binary_operation = None jump = None @@ -96,21 +100,29 @@ def unroll(self, program: Program) -> Program: if jump is None or label is None or binary_operation is None or badloop: self.log.warn("Bad or Infinite Loop Detected... aborting unroll") continue + # EXECUTE # Warning 0: This Code Works assuming the right is the constant # Warning 1: This Code is not fully functional: it cannot find the original x value constant = 1 base_instructions = program.functions[root]['blocks'][child].instructions.copy() - while self.finite_loop(binary_operation,constant,int(binary_operation.right),label.right.value) \ - and self.loop_condition(label.relop.value, constant, label.right.value): + is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) + while is_finite & self.loop_condition(label.relop.value, constant, label.right.value): program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) + # CLEANUP: Pops Parent, adds jump, redoes the labels. - jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.append(jump) - program.functions[root]['blocks'].pop(parent) - program.functions[root]['blocks'][child].label = label.true_branch - program.functions[root]['blocks'][child].jumps.pop() + + if is_finite: + jump.jumps = label.false_branch + program.functions[root]['blocks'][child].instructions.append(jump) + program.functions[root]['blocks'].pop(parent) + program.functions[root]['blocks'][child].label = label.true_branch + program.functions[root]['blocks'][child].jumps.pop() + else: + program.functions[root]['blocks'][parent].instructions = pure_parent_ins + program.functions[root]['blocks'][child].instructions = pure_child_ins + for root in program.functions: for block in program.functions[root]['blocks']: From 8f8a0e2b394090244ddef1cdeaeb03784b3c829a Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 11:53:04 -0700 Subject: [PATCH 34/48] Bad Loops and Unrollable Loops both handled correctly, small optimizations --- compiler/passes/transforms/loop_unroll.py | 31 ++++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 82b8db1..a6d2813 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -86,9 +86,7 @@ def unroll(self, program: Program) -> Program: for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: self.log.warn("Success") - # TODO: Better Binar - #IDENTyOp Chec - # 4 Cases: + # TODO: Better Binary Detection binary_operation = program.functions[root]['blocks'][child].instructions.pop( program.functions[root]['blocks'][child].instructions.index(c_instructions)) if binary_operation.defs.name[:-1] == l_left.name: @@ -97,31 +95,34 @@ def unroll(self, program: Program) -> Program: badloop = False else: pass - if jump is None or label is None or binary_operation is None or badloop: - self.log.warn("Bad or Infinite Loop Detected... aborting unroll") - continue + if jump is None or label is None or binary_operation is None: + badloop = True # EXECUTE # Warning 0: This Code Works assuming the right is the constant # Warning 1: This Code is not fully functional: it cannot find the original x value - constant = 1 - base_instructions = program.functions[root]['blocks'][child].instructions.copy() - is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) - while is_finite & self.loop_condition(label.relop.value, constant, label.right.value): - program.functions[root]['blocks'][child].instructions.extend(base_instructions) - constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) - - # CLEANUP: Pops Parent, adds jump, redoes the labels. - + if badloop is False: + constant = 1 + base_instructions = program.functions[root]['blocks'][child].instructions.copy() + is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), + label.right.value) if is_finite: + while self.loop_condition(label.relop.value, constant, label.right.value): + program.functions[root]['blocks'][child].instructions.extend(base_instructions) + constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) + # CLEANUP: Pops Parent, adds jump, redoes the labels. jump.jumps = label.false_branch program.functions[root]['blocks'][child].instructions.append(jump) program.functions[root]['blocks'].pop(parent) program.functions[root]['blocks'][child].label = label.true_branch program.functions[root]['blocks'][child].jumps.pop() else: + badloop = True + + if badloop: program.functions[root]['blocks'][parent].instructions = pure_parent_ins program.functions[root]['blocks'][child].instructions = pure_child_ins + self.log.warn("Found Unrollable Loop... resetting instructions..") for root in program.functions: From 2eabc32d4571f5bdef8b45e96cb6ef9a0ee536e7 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 14:13:44 -0700 Subject: [PATCH 35/48] Conditionals Work Correctly, however nested conditionals imply a control loop, which is not done by loop unrolling. --- compiler/passes/transforms/loop_unroll.py | 43 ++++++++++++++--------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index a6d2813..c3c1404 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -57,12 +57,17 @@ def unroll(self, program: Program) -> Program: global jump for root in program.functions: tlist = list(nx.simple_cycles(program.functions[root]['graph'])) + self.log.warn(tlist) for item in tlist: + if len(item) > 2: + continue child = item[1] parent = item[0] pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) + c_label = program.functions[root]['blocks'][child].label + label = None binary_operation = None jump = None @@ -72,17 +77,21 @@ def unroll(self, program: Program) -> Program: # Parent Instructions for p_instructions in program.functions[root]['blocks'][parent].instructions: if type(p_instructions) == Conditional: - self.log.warn("Success") - label = program.functions[root]['blocks'][parent].instructions.pop( - program.functions[root]['blocks'][parent].instructions.index(p_instructions)) - labels.append(label) - l_left = label.left - l_right = label.right + if c_label == p_instructions.true_branch: + + self.log.warn("Success") + label = program.functions[root]['blocks'][parent].instructions.pop( + program.functions[root]['blocks'][parent].instructions.index(p_instructions)) + labels.append(label) + l_left = label.left + l_right = label.right else: pass + + + bad_loop = True # Child Instructions jump = program.functions[root]['blocks'][child].instructions.pop(-1) - badloop = True for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: self.log.warn("Success") @@ -90,18 +99,20 @@ def unroll(self, program: Program) -> Program: binary_operation = program.functions[root]['blocks'][child].instructions.pop( program.functions[root]['blocks'][child].instructions.index(c_instructions)) if binary_operation.defs.name[:-1] == l_left.name: - badloop = False + bad_loop = False elif binary_operation.defs.name[:-1] == l_right.name: - badloop = False + bad_loop = False else: pass if jump is None or label is None or binary_operation is None: - badloop = True + bad_loop = True # EXECUTE - # Warning 0: This Code Works assuming the right is the constant + # Warning 0: This Code Works as + #IDENTyOp Chec + # 4 Cases:suming the right is the constant # Warning 1: This Code is not fully functional: it cannot find the original x value - if badloop is False: + if bad_loop is False: constant = 1 base_instructions = program.functions[root]['blocks'][child].instructions.copy() is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), @@ -117,14 +128,12 @@ def unroll(self, program: Program) -> Program: program.functions[root]['blocks'][child].label = label.true_branch program.functions[root]['blocks'][child].jumps.pop() else: - badloop = True + bad_loop = True - if badloop: + if bad_loop: program.functions[root]['blocks'][parent].instructions = pure_parent_ins program.functions[root]['blocks'][child].instructions = pure_child_ins self.log.warn("Found Unrollable Loop... resetting instructions..") - - for root in program.functions: for block in program.functions[root]['blocks']: self.log.warn(program.functions[root]['blocks'][block]) @@ -133,6 +142,8 @@ def unroll(self, program: Program) -> Program: return program # Entry Point + + def transform(self, program: Program) -> Program: for root in program.functions: for block in program.functions[root]['blocks']: From ef68fcaf9f06e67d2ec19b7ac5cef1e94f24edf9 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 15:31:11 -0700 Subject: [PATCH 36/48] Added Crash Prevention for Nested While Loops. Nested Loops do not unroll though --- compiler/passes/transforms/loop_unroll.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index c3c1404..f4f4b5c 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -63,7 +63,8 @@ def unroll(self, program: Program) -> Program: continue child = item[1] parent = item[0] - + self.log.warn(child) + self.log.warn(program.functions[root]['blocks'][1]) pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) c_label = program.functions[root]['blocks'][child].label @@ -75,6 +76,7 @@ def unroll(self, program: Program) -> Program: # IDENTIFY # TODO: Better Identification of Conditionals # Parent Instructions + l_left = l_right = None for p_instructions in program.functions[root]['blocks'][parent].instructions: if type(p_instructions) == Conditional: if c_label == p_instructions.true_branch: @@ -87,10 +89,9 @@ def unroll(self, program: Program) -> Program: l_right = label.right else: pass - - bad_loop = True # Child Instructions + jump = program.functions[root]['blocks'][child].instructions.pop(-1) for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: @@ -98,9 +99,9 @@ def unroll(self, program: Program) -> Program: # TODO: Better Binary Detection binary_operation = program.functions[root]['blocks'][child].instructions.pop( program.functions[root]['blocks'][child].instructions.index(c_instructions)) - if binary_operation.defs.name[:-1] == l_left.name: + if l_left != None and binary_operation.defs.name[:-1] == l_left.name: bad_loop = False - elif binary_operation.defs.name[:-1] == l_right.name: + elif l_right != None and binary_operation.defs.name[:-1] == l_right.name: bad_loop = False else: pass @@ -112,6 +113,7 @@ def unroll(self, program: Program) -> Program: #IDENTyOp Chec # 4 Cases:suming the right is the constant # Warning 1: This Code is not fully functional: it cannot find the original x value + is_finite = False if bad_loop is False: constant = 1 base_instructions = program.functions[root]['blocks'][child].instructions.copy() From df45fc35e64186b77b64a30402c075f81efbc595 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 26 Jun 2019 15:39:32 -0700 Subject: [PATCH 37/48] Pre-Demo Milestone 1 Commit --- compiler/passes/transforms/loop_unroll.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index f4f4b5c..053f6e9 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -42,7 +42,6 @@ def reevaluate(self, BO: BinaryOp, x, y): x = x | y return x - # TODO: Use "Induction" to determine finite loops def finite_loop(self, bin_op, x, y, z, inductive_step=True): k = self.reevaluate(bin_op, x, y) k_delta = k - z @@ -57,14 +56,11 @@ def unroll(self, program: Program) -> Program: global jump for root in program.functions: tlist = list(nx.simple_cycles(program.functions[root]['graph'])) - self.log.warn(tlist) for item in tlist: if len(item) > 2: continue child = item[1] parent = item[0] - self.log.warn(child) - self.log.warn(program.functions[root]['blocks'][1]) pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) c_label = program.functions[root]['blocks'][child].label @@ -74,7 +70,7 @@ def unroll(self, program: Program) -> Program: jump = None labels = [] # IDENTIFY - # TODO: Better Identification of Conditionals + # Parent Instructions l_left = l_right = None for p_instructions in program.functions[root]['blocks'][parent].instructions: @@ -144,8 +140,6 @@ def unroll(self, program: Program) -> Program: return program # Entry Point - - def transform(self, program: Program) -> Program: for root in program.functions: for block in program.functions[root]['blocks']: From 93f7f76a0d358c41b48be821c686554c10589a3c Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 1 Jul 2019 16:14:14 -0700 Subject: [PATCH 38/48] Planning Steps for Upgrading Identify stage to correctly identify all loops, not just cycles --- compiler/passes/transforms/loop_unroll.py | 24 +++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 053f6e9..c4ae843 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -51,16 +51,35 @@ def finite_loop(self, bin_op, x, y, z, inductive_step=True): else: i_step = True return True if zk_delta > 0 and i_step else False + def give_graph_loop(self,tlist): + # Algorithm Steps + # Let s be a set of nodes including header node h + # 1) for every node in s there is a path to h + # 2) from h there is a path to every node in s + # 3) there is no edge from any node outside S to any node in S other than h + + l_list = [] + return l_list def unroll(self, program: Program) -> Program: global jump for root in program.functions: + tlist = list(nx.simple_cycles(program.functions[root]['graph'])) + node_one = list(nx.nodes(program.functions[root]['graph'])) + # Step 1: Get cycle + # Step 2: Analyze Cycle + # This helps us verify condition 3: No outsinde inc edges + glist = program.functions[root]['graph'].in_edges(node_one[1]) + + self.log.warn(glist) + self.log.warn(tlist) for item in tlist: if len(item) > 2: continue child = item[1] parent = item[0] + pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) c_label = program.functions[root]['blocks'][child].label @@ -69,7 +88,7 @@ def unroll(self, program: Program) -> Program: binary_operation = None jump = None labels = [] - # IDENTIFY + # IDENTIFY - rewrite to implement dominator algorithm # Parent Instructions l_left = l_right = None @@ -111,7 +130,8 @@ def unroll(self, program: Program) -> Program: # Warning 1: This Code is not fully functional: it cannot find the original x value is_finite = False if bad_loop is False: - constant = 1 + constant = 1 # Can't get current variable value, assume 1 because we already have 1 "set" + # of instructions base_instructions = program.functions[root]['blocks'][child].instructions.copy() is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) From 74198c1b17a477f5e2b6796112c26e431877fd58 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 3 Jul 2019 12:19:22 -0700 Subject: [PATCH 39/48] Fixed Flow from Header to body in unrolled loops in the clean-up stage --- compiler/passes/transforms/loop_unroll.py | 24 ++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index c4ae843..c6b7185 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -5,6 +5,7 @@ import copy + class LoopUnroll(BSTransform): def __init__(self): @@ -51,15 +52,19 @@ def finite_loop(self, bin_op, x, y, z, inductive_step=True): else: i_step = True return True if zk_delta > 0 and i_step else False - def give_graph_loop(self,tlist): + def give_graph_loop(self,node_list): # Algorithm Steps - # Let s be a set of nodes including header node h - # 1) for every node in s there is a path to h - # 2) from h there is a path to every node in s - # 3) there is no edge from any node outside S to any node in S other than h - - l_list = [] - return l_list + # Given a list of cycles + # 1) for each item ,determine if the cycle is a loop + # 2) if all nodes of a loop are contained within another loop, + # put the smaller loop in front of the bigger loop in the order + # + for node in node_list: + # node_item = + # node_incoming = + + + return True def unroll(self, program: Program) -> Program: global jump @@ -142,7 +147,8 @@ def unroll(self, program: Program) -> Program: # CLEANUP: Pops Parent, adds jump, redoes the labels. jump.jumps = label.false_branch program.functions[root]['blocks'][child].instructions.append(jump) - program.functions[root]['blocks'].pop(parent) + jumpy = Jump(label.true_branch) + program.functions[root]['blocks'][parent].instructions.append(jumpy) program.functions[root]['blocks'][child].label = label.true_branch program.functions[root]['blocks'][child].jumps.pop() else: From 8fab50500cf3456d0516a523861b8a2597c3028e Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 3 Jul 2019 15:55:45 -0700 Subject: [PATCH 40/48] Loop Identification via dominators completed. Nested While Loops Work, Nested Conditionals, Multiple Conditionals, Multiple Loops --- compiler/passes/transforms/loop_unroll.py | 42 ++++++++++++----------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index c6b7185..34eb0f9 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -52,38 +52,41 @@ def finite_loop(self, bin_op, x, y, z, inductive_step=True): else: i_step = True return True if zk_delta > 0 and i_step else False - def give_graph_loop(self,node_list): + def give_loop_order(self,node_list): # Algorithm Steps - # Given a list of cycles - # 1) for each item ,determine if the cycle is a loop - # 2) if all nodes of a loop are contained within another loop, - # put the smaller loop in front of the bigger loop in the order - # - for node in node_list: - # node_item = - # node_incoming = - - - return True + # Detect: + # Get Immediate Dominators for every node + # Detect back-edges on each node + # Construct loop using intersection of ancestors of body and descendents of h + # Put loop set into list. + # Order loop list by non-containing nested first. + return node_list def unroll(self, program: Program) -> Program: global jump for root in program.functions: - tlist = list(nx.simple_cycles(program.functions[root]['graph'])) + tlist = [] node_one = list(nx.nodes(program.functions[root]['graph'])) + dominators = (nx.immediate_dominators(program.functions[root]['graph'],1)) + sorted_doms = sorted(dominators.items()) + for item in dominators: + edge_list = list(program.functions[root]['graph'].out_edges(item)) + if len(edge_list) > 0: + for edge in edge_list: + if edge in sorted_doms: + tlist.append(edge) + + # Step 1: Get cycle # Step 2: Analyze Cycle # This helps us verify condition 3: No outsinde inc edges - glist = program.functions[root]['graph'].in_edges(node_one[1]) - self.log.warn(glist) - self.log.warn(tlist) for item in tlist: if len(item) > 2: continue - child = item[1] - parent = item[0] + child = item[0] + parent = item[1] pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) @@ -101,7 +104,7 @@ def unroll(self, program: Program) -> Program: if type(p_instructions) == Conditional: if c_label == p_instructions.true_branch: - self.log.warn("Success") + label = program.functions[root]['blocks'][parent].instructions.pop( program.functions[root]['blocks'][parent].instructions.index(p_instructions)) labels.append(label) @@ -115,7 +118,6 @@ def unroll(self, program: Program) -> Program: jump = program.functions[root]['blocks'][child].instructions.pop(-1) for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: - self.log.warn("Success") # TODO: Better Binary Detection binary_operation = program.functions[root]['blocks'][child].instructions.pop( program.functions[root]['blocks'][child].instructions.index(c_instructions)) From 03e06052424a167dc84dee699fd9efde8f2aae83 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Wed, 3 Jul 2019 15:59:55 -0700 Subject: [PATCH 41/48] Minor Edits. Removed Herobrine --- compiler/passes/transforms/loop_unroll.py | 28 +++++------------------ 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 34eb0f9..fb6d30e 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -52,15 +52,6 @@ def finite_loop(self, bin_op, x, y, z, inductive_step=True): else: i_step = True return True if zk_delta > 0 and i_step else False - def give_loop_order(self,node_list): - # Algorithm Steps - # Detect: - # Get Immediate Dominators for every node - # Detect back-edges on each node - # Construct loop using intersection of ancestors of body and descendents of h - # Put loop set into list. - # Order loop list by non-containing nested first. - return node_list def unroll(self, program: Program) -> Program: global jump @@ -77,11 +68,6 @@ def unroll(self, program: Program) -> Program: if edge in sorted_doms: tlist.append(edge) - - # Step 1: Get cycle - # Step 2: Analyze Cycle - # This helps us verify condition 3: No outsinde inc edges - for item in tlist: if len(item) > 2: continue @@ -103,8 +89,6 @@ def unroll(self, program: Program) -> Program: for p_instructions in program.functions[root]['blocks'][parent].instructions: if type(p_instructions) == Conditional: if c_label == p_instructions.true_branch: - - label = program.functions[root]['blocks'][parent].instructions.pop( program.functions[root]['blocks'][parent].instructions.index(p_instructions)) labels.append(label) @@ -114,7 +98,6 @@ def unroll(self, program: Program) -> Program: pass bad_loop = True # Child Instructions - jump = program.functions[root]['blocks'][child].instructions.pop(-1) for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: @@ -132,13 +115,14 @@ def unroll(self, program: Program) -> Program: # EXECUTE # Warning 0: This Code Works as - #IDENTyOp Chec - # 4 Cases:suming the right is the constant + # IDENTyOp Chec + # 4 Cases:suming the right is the constant # Warning 1: This Code is not fully functional: it cannot find the original x value is_finite = False if bad_loop is False: - constant = 1 # Can't get current variable value, assume 1 because we already have 1 "set" - # of instructions + constant = 1 + # Can't get current variable value, assume 1 because we already have 1 "set" + # of instructions base_instructions = program.functions[root]['blocks'][child].instructions.copy() is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) @@ -149,7 +133,7 @@ def unroll(self, program: Program) -> Program: # CLEANUP: Pops Parent, adds jump, redoes the labels. jump.jumps = label.false_branch program.functions[root]['blocks'][child].instructions.append(jump) - jumpy = Jump(label.true_branch) + jumpy = Jump(label.true_branch) program.functions[root]['blocks'][parent].instructions.append(jumpy) program.functions[root]['blocks'][child].label = label.true_branch program.functions[root]['blocks'][child].jumps.pop() From 79b4e00e4228a9795fa864c93cd35836e838a36a Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 8 Jul 2019 12:30:24 -0700 Subject: [PATCH 42/48] Fixed While Loop Labels, Updated Loop Unrolling --- compiler/passes/transforms/loop_unroll.py | 33 +++++++++++++++++------ compiler/semantics/ir_visitor.py | 6 ++--- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index fb6d30e..0b738aa 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -88,29 +88,40 @@ def unroll(self, program: Program) -> Program: l_left = l_right = None for p_instructions in program.functions[root]['blocks'][parent].instructions: if type(p_instructions) == Conditional: - if c_label == p_instructions.true_branch: + if c_label.label == p_instructions.true_branch.label: label = program.functions[root]['blocks'][parent].instructions.pop( program.functions[root]['blocks'][parent].instructions.index(p_instructions)) + self.log.warn(label) labels.append(label) l_left = label.left + l_right = label.right + else: + self.log.warn(p_instructions.true_branch) + self.log.warn(c_label) + self.log.warn(p_instructions.true_branch == c_label) else: pass bad_loop = True # Child Instructions - jump = program.functions[root]['blocks'][child].instructions.pop(-1) + # TODO: Fix Child end Jump Detection + if program.functions[root]['blocks'][child].instructions[-1] == Jump: + jump = program.functions[root]['blocks'][child].instructions.pop(-1) + else: + jump = None for c_instructions in program.functions[root]['blocks'][child].instructions: if type(c_instructions) == BinaryOp: - # TODO: Better Binary Detection - binary_operation = program.functions[root]['blocks'][child].instructions.pop( - program.functions[root]['blocks'][child].instructions.index(c_instructions)) + binary_operation = c_instructions if l_left != None and binary_operation.defs.name[:-1] == l_left.name: + program.functions[root]['blocks'][child].instructions.pop(program.functions[root]['blocks'][child].instructions.index(c_instructions)) bad_loop = False elif l_right != None and binary_operation.defs.name[:-1] == l_right.name: + program.functions[root]['blocks'][child].instructions.pop(program.functions[root]['blocks'][child].instructions.index(c_instructions)) bad_loop = False else: pass - if jump is None or label is None or binary_operation is None: + if label is None or binary_operation is None: + self.log.warn("I fail on the initial bad loop!") bad_loop = True # EXECUTE @@ -120,6 +131,7 @@ def unroll(self, program: Program) -> Program: # Warning 1: This Code is not fully functional: it cannot find the original x value is_finite = False if bad_loop is False: + self.log.warn("I fail on the binaryop check!") constant = 1 # Can't get current variable value, assume 1 because we already have 1 "set" # of instructions @@ -131,13 +143,18 @@ def unroll(self, program: Program) -> Program: program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) # CLEANUP: Pops Parent, adds jump, redoes the labels. - jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.append(jump) + + if jump is not None: + jump.jumps = label.false_branch + program.functions[root]['blocks'][child].instructions.append(jump) + jumpy = Jump(label.true_branch) program.functions[root]['blocks'][parent].instructions.append(jumpy) program.functions[root]['blocks'][child].label = label.true_branch + program.functions[root]['blocks'][child].jumps.pop() else: + self.log.warn("I fail on the finite check!") bad_loop = True if bad_loop: diff --git a/compiler/semantics/ir_visitor.py b/compiler/semantics/ir_visitor.py index 62c722f..de20be0 100644 --- a/compiler/semantics/ir_visitor.py +++ b/compiler/semantics/ir_visitor.py @@ -265,7 +265,7 @@ def visitWhileStatement(self, ctx: BSParser.WhileStatementContext): self.scope_stack[-1], value=float(par_expression['exp2']), is_constant=True) self.symbol_table.add_local(exp2, self.scope_stack[-1]) else: - exp2 = par_expression['exp2'] + exp2 = self.allocation_map[par_expression['exp2']] pre_condition_label_string = "bsbbw_{}_l".format(self.current_block.nid) pre_condition_label = Label(pre_condition_label_string) @@ -276,7 +276,7 @@ def visitWhileStatement(self, ctx: BSParser.WhileStatementContext): condition = Conditional(par_expression['op'], exp1, exp2) true_block = BasicBlock() self.graph.add_node(true_block.nid, function=self.scope_stack[-1]) - true_label = Label("bsbbw_{}_t".format(self.current_block.nid)) + true_label = Label("bsbbw_{}_l".format(true_block.nid)) self.labels[true_label.name] = true_block.nid true_block.add(true_label) @@ -361,7 +361,7 @@ def visitRepeat(self, ctx: BSParser.RepeatContext): condition = Conditional(par_expression['op'], exp1, exp2) true_block = BasicBlock() self.graph.add_node(true_block.nid, function=self.scope_stack[-1]) - true_label = Label("bsbbw_{}_t".format(self.current_block.nid)) + true_label = Label("bsbbw_{}_l".format(true_block.nid)) self.labels[true_label.name] = true_block.nid true_block.add(true_label) From 14ae210f3b65e6a7461a175a6cef376384112cf9 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 8 Jul 2019 12:40:39 -0700 Subject: [PATCH 43/48] Fixed Nested Loop Multipliers --- compiler/passes/transforms/loop_unroll.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 0b738aa..8b97611 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -83,7 +83,7 @@ def unroll(self, program: Program) -> Program: jump = None labels = [] # IDENTIFY - rewrite to implement dominator algorithm - + nested_multiplier = 0 # Parent Instructions l_left = l_right = None for p_instructions in program.functions[root]['blocks'][parent].instructions: @@ -91,15 +91,12 @@ def unroll(self, program: Program) -> Program: if c_label.label == p_instructions.true_branch.label: label = program.functions[root]['blocks'][parent].instructions.pop( program.functions[root]['blocks'][parent].instructions.index(p_instructions)) - self.log.warn(label) + nested_multiplier +=1 labels.append(label) l_left = label.left l_right = label.right - else: - self.log.warn(p_instructions.true_branch) - self.log.warn(c_label) - self.log.warn(p_instructions.true_branch == c_label) + else: pass bad_loop = True @@ -121,7 +118,6 @@ def unroll(self, program: Program) -> Program: else: pass if label is None or binary_operation is None: - self.log.warn("I fail on the initial bad loop!") bad_loop = True # EXECUTE @@ -131,7 +127,6 @@ def unroll(self, program: Program) -> Program: # Warning 1: This Code is not fully functional: it cannot find the original x value is_finite = False if bad_loop is False: - self.log.warn("I fail on the binaryop check!") constant = 1 # Can't get current variable value, assume 1 because we already have 1 "set" # of instructions @@ -139,7 +134,7 @@ def unroll(self, program: Program) -> Program: is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) if is_finite: - while self.loop_condition(label.relop.value, constant, label.right.value): + while self.loop_condition(label.relop.value, constant, label.right.value*nested_multiplier): program.functions[root]['blocks'][child].instructions.extend(base_instructions) constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) # CLEANUP: Pops Parent, adds jump, redoes the labels. @@ -154,7 +149,6 @@ def unroll(self, program: Program) -> Program: program.functions[root]['blocks'][child].jumps.pop() else: - self.log.warn("I fail on the finite check!") bad_loop = True if bad_loop: From 1af70273ec001e5d588175be1e75b392f8de708e Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 8 Jul 2019 13:28:17 -0700 Subject: [PATCH 44/48] Refactored Jump handling in loops --- compiler/passes/transforms/loop_unroll.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 8b97611..852b694 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -130,24 +130,26 @@ def unroll(self, program: Program) -> Program: constant = 1 # Can't get current variable value, assume 1 because we already have 1 "set" # of instructions - base_instructions = program.functions[root]['blocks'][child].instructions.copy() + base_instructions_unf = program.functions[root]['blocks'][child].instructions.copy() + base_instructions = list(filter(lambda i : not(type(i) is Jump), base_instructions_unf)) + program.functions[root]['blocks'][child].instructions = base_instructions.copy() is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) if is_finite: while self.loop_condition(label.relop.value, constant, label.right.value*nested_multiplier): - program.functions[root]['blocks'][child].instructions.extend(base_instructions) + program.functions[root]['blocks'][child].instructions +=base_instructions constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) # CLEANUP: Pops Parent, adds jump, redoes the labels. - if jump is not None: jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.append(jump) + program.functions[root]['blocks'][child].instructions.extend(jump) jumpy = Jump(label.true_branch) program.functions[root]['blocks'][parent].instructions.append(jumpy) program.functions[root]['blocks'][child].label = label.true_branch program.functions[root]['blocks'][child].jumps.pop() + program.functions[root]['blocks'][child].instructions.append(Jump(program.functions[root]['blocks'][child+1].label)) else: bad_loop = True From dce5272bc9b037402b4aa0ac140e276b5b447411 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 8 Jul 2019 13:54:31 -0700 Subject: [PATCH 45/48] Pre-Pull Request Code Cleanup --- compiler/passes/transforms/loop_unroll.py | 177 ++++++++++------------ 1 file changed, 84 insertions(+), 93 deletions(-) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 852b694..9dc0854 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -12,85 +12,84 @@ def __init__(self): super().__init__("LoopUnravel") self.log.warn("Starting Loop Unrolling.....") - def loop_condition(self, RO, x, y): - if RO == RelationalOps.EQUALITY: - return True if x == y else False - elif RO == RelationalOps.NE: - return True if x != y else False - elif RO == RelationalOps.LT: - return True if x < y else False - elif RO == RelationalOps.LTE: - return True if x <= y else False - elif RO == RelationalOps.GT: - return True if x > y else False - elif RO == RelationalOps.GTE: - return True if x >= y else False + def loop_condition(self, RelOp, left, right): + if RelOp == RelationalOps.EQUALITY: + return True if left == right else False + elif RelOp == RelationalOps.NE: + return True if left != right else False + elif RelOp == RelationalOps.LT: + return True if left < right else False + elif RelOp == RelationalOps.LTE: + return True if left <= right else False + elif RelOp == RelationalOps.GT: + return True if left > right else False + elif RelOp == RelationalOps.GTE: + return True if left >= right else False else: return False - def reevaluate(self, BO: BinaryOp, x, y): - if BO.op == BinaryOps.SUBTRACT: - x = x - y - elif BO.op == BinaryOps.ADD: - x = x + y - elif BO.op == BinaryOps.MULTIPLE: - x = x * y - elif BO.op == BinaryOps.DIVIDE: - x = x / y - elif BO.op == BinaryOps.AND: - x = x & y - elif BO.op == BinaryOps.OR: - x = x | y - return x - - def finite_loop(self, bin_op, x, y, z, inductive_step=True): - k = self.reevaluate(bin_op, x, y) - k_delta = k - z - zx_delta = x - z - zk_delta = abs(zx_delta) - abs(k_delta) - if inductive_step: i_step = self.finite_loop(bin_op, k, y, z, False) + def reevaluate(self, BinOp: BinaryOp, left, right): + if BinOp.op == BinaryOps.SUBTRACT: + left = left - right + elif BinOp.op == BinaryOps.ADD: + left = left + right + elif BinOp.op == BinaryOps.MULTIPLE: + left = left * right + elif BinOp.op == BinaryOps.DIVIDE: + left = left / right + elif BinOp.op == BinaryOps.AND: + left = left & right + elif BinOp.op == BinaryOps.OR: + left = left | right + return left + + def finite_loop(self, bin_op, left: int, modifier: int, right: int, inductive_step=True): + left_modified = self.reevaluate(bin_op, left, modifier) + left_modified_right_delta = left_modified - right + left_right_delta = left - right + lmrd_lrd_delta = left_right_delta - left_modified_right_delta + if inductive_step: i_step = self.finite_loop(bin_op, left_modified, modifier, right, False) else: i_step = True - return True if zk_delta > 0 and i_step else False + return True if abs(lmrd_lrd_delta) > 0 and i_step else False def unroll(self, program: Program) -> Program: - global jump + global jump_from_loop_body for root in program.functions: - tlist = [] - node_one = list(nx.nodes(program.functions[root]['graph'])) + loop_list = [] dominators = (nx.immediate_dominators(program.functions[root]['graph'],1)) sorted_doms = sorted(dominators.items()) - for item in dominators: - edge_list = list(program.functions[root]['graph'].out_edges(item)) + for loop in dominators: + edge_list = list(program.functions[root]['graph'].out_edges(loop)) if len(edge_list) > 0: for edge in edge_list: if edge in sorted_doms: - tlist.append(edge) + loop_list.append(edge) - for item in tlist: - if len(item) > 2: + for loop in loop_list: + if len(loop) > 2: continue - child = item[0] - parent = item[1] + loop_body = loop[0] + head = loop[1] - pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][child].instructions) - pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][parent].instructions) - c_label = program.functions[root]['blocks'][child].label + pure_child_ins = copy.deepcopy(program.functions[root]['blocks'][loop_body].instructions) + pure_parent_ins = copy.deepcopy(program.functions[root]['blocks'][head].instructions) + c_label = program.functions[root]['blocks'][loop_body].label label = None binary_operation = None - jump = None + jump_from_loop_body = None labels = [] - # IDENTIFY - rewrite to implement dominator algorithm + # IDENTIFY nested_multiplier = 0 - # Parent Instructions + # Head Instructions l_left = l_right = None - for p_instructions in program.functions[root]['blocks'][parent].instructions: + for p_instructions in program.functions[root]['blocks'][head].instructions: if type(p_instructions) == Conditional: if c_label.label == p_instructions.true_branch.label: - label = program.functions[root]['blocks'][parent].instructions.pop( - program.functions[root]['blocks'][parent].instructions.index(p_instructions)) + label = program.functions[root]['blocks'][head].instructions.pop( + program.functions[root]['blocks'][head].instructions.index(p_instructions)) nested_multiplier +=1 labels.append(label) l_left = label.left @@ -100,20 +99,19 @@ def unroll(self, program: Program) -> Program: else: pass bad_loop = True - # Child Instructions - # TODO: Fix Child end Jump Detection - if program.functions[root]['blocks'][child].instructions[-1] == Jump: - jump = program.functions[root]['blocks'][child].instructions.pop(-1) + + if program.functions[root]['blocks'][loop_body].instructions[-1] == Jump: + jump_from_loop_body = program.functions[root]['blocks'][loop_body].instructions.pop(-1) else: - jump = None - for c_instructions in program.functions[root]['blocks'][child].instructions: + jump_from_loop_body = None + for c_instructions in program.functions[root]['blocks'][loop_body].instructions: if type(c_instructions) == BinaryOp: binary_operation = c_instructions if l_left != None and binary_operation.defs.name[:-1] == l_left.name: - program.functions[root]['blocks'][child].instructions.pop(program.functions[root]['blocks'][child].instructions.index(c_instructions)) + program.functions[root]['blocks'][loop_body].instructions.pop(program.functions[root]['blocks'][loop_body].instructions.index(c_instructions)) bad_loop = False elif l_right != None and binary_operation.defs.name[:-1] == l_right.name: - program.functions[root]['blocks'][child].instructions.pop(program.functions[root]['blocks'][child].instructions.index(c_instructions)) + program.functions[root]['blocks'][loop_body].instructions.pop(program.functions[root]['blocks'][loop_body].instructions.index(c_instructions)) bad_loop = False else: pass @@ -121,55 +119,48 @@ def unroll(self, program: Program) -> Program: bad_loop = True # EXECUTE - # Warning 0: This Code Works as - # IDENTyOp Chec - # 4 Cases:suming the right is the constant - # Warning 1: This Code is not fully functional: it cannot find the original x value + # TODO: Refactor when Numbers are fixed is_finite = False if bad_loop is False: constant = 1 - # Can't get current variable value, assume 1 because we already have 1 "set" - # of instructions - base_instructions_unf = program.functions[root]['blocks'][child].instructions.copy() + + base_instructions_unf = program.functions[root]['blocks'][loop_body].instructions.copy() base_instructions = list(filter(lambda i : not(type(i) is Jump), base_instructions_unf)) - program.functions[root]['blocks'][child].instructions = base_instructions.copy() + program.functions[root]['blocks'][loop_body].instructions = base_instructions.copy() is_finite = self.finite_loop(binary_operation, constant, int(binary_operation.right), label.right.value) if is_finite: while self.loop_condition(label.relop.value, constant, label.right.value*nested_multiplier): - program.functions[root]['blocks'][child].instructions +=base_instructions + program.functions[root]['blocks'][loop_body].instructions +=base_instructions constant = self.reevaluate(binary_operation, constant, int(binary_operation.right)) - # CLEANUP: Pops Parent, adds jump, redoes the labels. - if jump is not None: - jump.jumps = label.false_branch - program.functions[root]['blocks'][child].instructions.extend(jump) + # CLEANUP: Adds the correct jump paths + if jump_from_loop_body is not None: + jump_from_loop_body.jumps = label.false_branch + program.functions[root]['blocks'][loop_body].instructions.extend(jump_from_loop_body) - jumpy = Jump(label.true_branch) - program.functions[root]['blocks'][parent].instructions.append(jumpy) - program.functions[root]['blocks'][child].label = label.true_branch + jump_from_head = Jump(label.true_branch) + program.functions[root]['blocks'][head].instructions.append(jump_from_head) + program.functions[root]['blocks'][loop_body].label = label.true_branch - program.functions[root]['blocks'][child].jumps.pop() - program.functions[root]['blocks'][child].instructions.append(Jump(program.functions[root]['blocks'][child+1].label)) + program.functions[root]['blocks'][loop_body].jumps.pop() + program.functions[root]['blocks'][loop_body].instructions.append(Jump(program.functions[root]['blocks'][loop_body+1].label)) else: bad_loop = True if bad_loop: - program.functions[root]['blocks'][parent].instructions = pure_parent_ins - program.functions[root]['blocks'][child].instructions = pure_child_ins + program.functions[root]['blocks'][head].instructions = pure_parent_ins + program.functions[root]['blocks'][loop_body].instructions = pure_child_ins self.log.warn("Found Unrollable Loop... resetting instructions..") - for root in program.functions: - for block in program.functions[root]['blocks']: - self.log.warn(program.functions[root]['blocks'][block]) - self.log.warn("Loop Unrolling Completed") - # Test code showing program post unroll + # for root in program.functions: + # for block in program.functions[root]['blocks']: + # self.log.warn(program.functions[root]['blocks'][block]) + # self.log.warn("Loop Unrolling Completed") return program # Entry Point def transform(self, program: Program) -> Program: - for root in program.functions: - for block in program.functions[root]['blocks']: - self.log.warn(program.functions[root]['blocks'][block]) - self.log.warn("Loop Unrolling Completed") - # Test Print to show pre-unroll - # Test function + # for root in program.functions: + # for block in program.functions[root]['blocks']: + # self.log.warn(program.functions[root]['blocks'][block]) + # self.log.warn("Loop Unrolling Completed") return self.unroll(program) From 5598821fdf4876ada00b14675fb5e77a0cc75ac3 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Mon, 8 Jul 2019 13:59:18 -0700 Subject: [PATCH 46/48] Revert exp2 change in visit_while --- compiler/semantics/ir_visitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/semantics/ir_visitor.py b/compiler/semantics/ir_visitor.py index de20be0..fc9284d 100644 --- a/compiler/semantics/ir_visitor.py +++ b/compiler/semantics/ir_visitor.py @@ -265,7 +265,7 @@ def visitWhileStatement(self, ctx: BSParser.WhileStatementContext): self.scope_stack[-1], value=float(par_expression['exp2']), is_constant=True) self.symbol_table.add_local(exp2, self.scope_stack[-1]) else: - exp2 = self.allocation_map[par_expression['exp2']] + exp2 = par_expression['exp2'] pre_condition_label_string = "bsbbw_{}_l".format(self.current_block.nid) pre_condition_label = Label(pre_condition_label_string) From dcaed8af33773684c5df73e7e9242f4ab937c638 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Thu, 11 Jul 2019 19:11:06 -0700 Subject: [PATCH 47/48] Confirming Muffin Man Contact --- compiler/passes/transforms/loop_unroll.py | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 9dc0854..5eef694 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -155,6 +155,7 @@ def unroll(self, program: Program) -> Program: # for block in program.functions[root]['blocks']: # self.log.warn(program.functions[root]['blocks'][block]) # self.log.warn("Loop Unrolling Completed") + # I know the muffin man return program # Entry Point From aac4705f1e676c1dd3147a032eb4d817089a7fb4 Mon Sep 17 00:00:00 2001 From: startwarfields Date: Fri, 12 Jul 2019 13:13:39 -0700 Subject: [PATCH 48/48] Testing mfsim reimplementation --- compiler/passes/pass_manager.py | 4 ++-- compiler/passes/transforms/loop_unroll.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/passes/pass_manager.py b/compiler/passes/pass_manager.py index 434fc64..d555984 100644 --- a/compiler/passes/pass_manager.py +++ b/compiler/passes/pass_manager.py @@ -5,6 +5,7 @@ from compiler.passes.analyses.call_graph import CallGraph from compiler.passes.analyses.def_use import DefUseChains from compiler.passes.transforms.inline import Inline +from compiler.passes.transforms.loop_unroll import LoopUnroll from compiler.passes.transforms.split_edges import SplitEdges from compiler.passes.transforms.ssa import SSA from shared.bs_exceptions import UnInitializedError @@ -39,8 +40,6 @@ def run_transformations(self): # TODO: This should be handled through decorator. # TODO: Make this handle dependencies correctly. for key, value in self.transforms.items(): - if key is 'loop_unroll' and not self.config.loopunroll: - continue self.program = value.transform(self.program) def run_analysis(self): @@ -60,4 +59,5 @@ def init_transforms(self): if self.config.inline: self.transforms['inline'] = Inline() self.transforms['split_edges'] = SplitEdges() + self.transforms['loop_unroll'] = LoopUnroll() self.dependencies['transforms'].add_node('split_edges') diff --git a/compiler/passes/transforms/loop_unroll.py b/compiler/passes/transforms/loop_unroll.py index 5eef694..a89bc34 100644 --- a/compiler/passes/transforms/loop_unroll.py +++ b/compiler/passes/transforms/loop_unroll.py @@ -56,7 +56,7 @@ def finite_loop(self, bin_op, left: int, modifier: int, right: int, inductive_st def unroll(self, program: Program) -> Program: global jump_from_loop_body for root in program.functions: - + self.log.warn("Test") loop_list = [] dominators = (nx.immediate_dominators(program.functions[root]['graph'],1)) sorted_doms = sorted(dominators.items()) @@ -151,17 +151,17 @@ def unroll(self, program: Program) -> Program: program.functions[root]['blocks'][head].instructions = pure_parent_ins program.functions[root]['blocks'][loop_body].instructions = pure_child_ins self.log.warn("Found Unrollable Loop... resetting instructions..") - # for root in program.functions: - # for block in program.functions[root]['blocks']: - # self.log.warn(program.functions[root]['blocks'][block]) - # self.log.warn("Loop Unrolling Completed") - # I know the muffin man + for root in program.functions: + for block in program.functions[root]['blocks']: + self.log.warn(program.functions[root]['blocks'][block]) + self.log.warn("Loop Unrolling Completed") return program # Entry Point def transform(self, program: Program) -> Program: - # for root in program.functions: - # for block in program.functions[root]['blocks']: - # self.log.warn(program.functions[root]['blocks'][block]) - # self.log.warn("Loop Unrolling Completed") + for root in program.functions: + for block in program.functions[root]['blocks']: + self.log.warn("I exist! i matter! ") + self.log.warn(program.functions[root]['blocks'][block]) + self.log.warn("Loop Unrolling Completed") return self.unroll(program)