source: proto/Compiler/CCGO.py @ 2693

Last change on this file since 2693 was 2693, checked in by cameron, 7 years ago

Create separate CCGO module

File size: 6.6 KB
Line 
1#
2# CCGO.py
3#
4# Copyright 2012, Robert D. Cameron
5# All rights reserved.
6#
7# Carry Code Generator Objects (CCGOs)
8#
9# CCGOs are objects which implement a particular strategy for incorporating
10# carry processing into generated Pablo code.
11#
12# A CCGO consists of methods that can be used to insert carry processing
13# code at particular locations in a Pablo program.   The CCGO is intended
14# to be a parameter to a CarryIntro tree transformer, abstracting away
15# the strategy from the tree traversal to apply the strategy to
16# a particular stream function.
17#
18import ast
19#
20# The base CCGO Class is also the null class, suitable for stream
21# functions that have no carry-generating operations.
22#
23class CCGO:
24    def __init__(self): pass
25    def GenerateCarryDecls(self): return ""
26    def GenerateInitializations(self): return ""
27    def GenerateStreamFunctionDecls(self):  return ""
28    def GenerateCarryInAccess(self, operation_no): return None
29    def GenerateCarryOutStore(self, operation_no, carry_out_expr): return []
30    def GenerateCarryIfTest(self, block_no, ifTest): return ifTest
31    def GenerateCarryElseFinalization(self, block_no): return []
32    def GenerateLocalDeclare(self, block_no): return []
33    def GenerateCarryWhileTest(self, block_no, testExpr): return testExpr
34    def EnterLocalWhileBlock(self, operation_offset):  pass
35    def ExitLocalWhileBlock(self):  pass
36    def GenerateCarryWhileFinalization(self, block_no): return []
37    def GenerateStreamFunctionFinalization(self): return []
38
39#
40# Helpers
41def mkCall(fn_name, args):
42  if isinstance(fn_name, str): 
43        fn_name = ast.Name(fn_name, ast.Load())
44  return ast.Call(fn_name, args, [], None, None)
45
46def mkCallStmt(fn_name, args):
47  if isinstance(fn_name, str): fn_name = ast.Name(fn_name, ast.Load())
48  return ast.Expr(ast.Call(fn_name, args, [], None, None))
49 
50 
51#
52#  The testCCGO is a legacy class designed to duplicate the previous Pablo
53#  functionality of introducing a set of abstract macros into generated
54#  code (CarryArray, CarryTest, CarryDequeueEnqueue, CarryAdjust, etc.)
55#
56class testCCGO(CCGO):
57    def __init__(self, carryInfoSet, carryGroupVarName='carryQ'):
58        self.carryInfoSet = carryInfoSet
59        self.carryGroupVar = carryGroupVarName
60        self.carryIndex = {}
61        self.operation_offset = 0
62        carry_counter = 0
63        for op_no in range(carryInfoSet.operation_count):
64          self.carryIndex[op_no] = carry_counter
65          if not op_no in carryInfoSet.advance_amount.keys(): carry_counter += 1
66          elif carryInfoSet.advance_amount[op_no] == 1: carry_counter += 1
67        # Add a dummy entry for any possible final block that is empty.
68        self.carryIndex[carryInfoSet.operation_count] = carry_counter
69    # Helper
70    def CarryGroupAtt(self, attname, CarryGroupVarName=""):
71        if CarryGroupVarName == '': CarryGroupVarName = self.carryGroupVar
72        return ast.Attribute(ast.Name(CarryGroupVarName, ast.Load()), attname, ast.Load())
73    def GenerateCarryDecls(self):
74        carry_counter = 0
75        adv_n_counter = 0
76        for op_no in range(self.carryInfoSet.block_op_count[0]):
77          if not op_no in self.carryInfoSet.advance_amount.keys(): carry_counter += 1
78          elif self.carryInfoSet.advance_amount[op_no] == 1: carry_counter += 1
79          else: adv_n_counter += 1
80        return "CarryArray<%i, %i> %s;" % (carry_counter, adv_n_counter, self.carryGroupVar)
81    def GenerateInitializations(self):
82        carry_counter = 0
83        adv_n_counter = 0
84        inits = ""
85        for op_no in range(self.carryInfoSet.block_op_count[0]):
86          if op_no in self.carryInfoSet.init_one_list: inits += "carryQ.cq[%s] = carryQ.carry_flip(carryQ.cq[%s]);\n" % (carry_counter, carry_counter)
87          if not op_no in self.carryInfoSet.advance_amount.keys(): carry_counter += 1
88          elif self.carryInfoSet.advance_amount[op_no] == 1: carry_counter += 1
89          else: adv_n_counter += 1
90        return inits
91    def GenerateStreamFunctionDecls(self):  return ""
92    def GenerateCarryInAccess(self, operation_no):
93        carry_index = self.carryIndex[operation_no - self.operation_offset]
94        return mkCall(self.carryGroupVar + "." + 'get_carry_in', [ast.Num(carry_index)])
95    def GenerateCarryOutStore(self, operation_no, carry_out_expr):
96        carry_index = self.carryIndex[operation_no - self.operation_offset]
97        return [ast.Assign([ast.Subscript(self.CarryGroupAtt('cq'), ast.Index(ast.Num(carry_index)), ast.Store())], 
98                          mkCall("bitblock::srli<127>", [carry_out_expr]))]
99    def GenerateCarryIfTest(self, block_no, ifTest):
100        carry_count = self.carryInfoSet.block_op_count[block_no]
101        if carry_count == 0: return ifTest
102        ifIndex = self.carryIndex[self.carryInfoSet.block_first_op[block_no]]       
103        return ast.BoolOp(ast.Or(), [ifTest, mkCall(self.CarryGroupAtt('CarryTest'), [ast.Num(ifIndex), ast.Num(carry_count)])])
104    def GenerateCarryElseFinalization(self, block_no): 
105        carry_count = self.carryInfoSet.block_op_count[block_no]
106        if carry_count == 0: return []
107        ifIndex = self.carryIndex[self.carryInfoSet.block_first_op[block_no]]       
108        return [mkCallStmt(self.CarryGroupAtt('CarryDequeueEnqueue'), [ast.Num(ifIndex), ast.Num(carry_count)])]
109    def GenerateLocalDeclare(self, block_no):
110        local_carryvar = ast.Name("sub" + self.carryGroupVar, ast.Load())
111        return [mkCallStmt('LocalCarryDeclare', [local_carryvar, ast.Num(self.carryInfoSet.block_op_count[block_no])])]
112    def GenerateCarryWhileTest(self, block_no, testExpr):
113        carry_count = self.carryInfoSet.block_op_count[block_no]
114        if carry_count == 0: return testExpr
115        carry0 = self.carryIndex[self.carryInfoSet.block_first_op[block_no]]       
116        return ast.BoolOp(ast.Or(), [testExpr, mkCall(self.CarryGroupAtt('CarryTest'), [ast.Num(carry0), ast.Num(carry_count)])])
117    def EnterLocalWhileBlock(self, operation_offset): 
118        self.carryGroupVar = "sub" + self.carryGroupVar
119        self.operation_offset = operation_offset
120    def ExitLocalWhileBlock(self): 
121        self.operation_offset = 0
122        self.carryGroupVar = self.carryGroupVar[3:]
123    def GenerateCarryWhileFinalization(self, block_no): 
124        carry_count = self.carryInfoSet.block_op_count[block_no]
125        if carry_count == 0: return []
126        loopIndex = self.carryIndex[self.carryInfoSet.block_first_op[block_no]]       
127        return [mkCallStmt(self.CarryGroupAtt('CarryCombine'), [self.CarryGroupAtt('cq', "sub" + self.carryGroupVar), ast.Num(loopIndex), ast.Num(carry_count)])]
128    def GenerateStreamFunctionFinalization(self):
129        carry_count = self.carryInfoSet.countBlockCarrysWithAdv1(0)
130        if carry_count == 0: return []
131        else: return [mkCallStmt(self.CarryGroupAtt('CarryQ_Adjust'), [ast.Num(carry_count)])]
132
Note: See TracBrowser for help on using the repository browser.