source: proto/Compiler/CCGO_HMCPS.py @ 2799

Last change on this file since 2799 was 2799, checked in by cameron, 6 years ago

Separate allocation from init, add BLOCK_SIZE parameter, tidy

File size: 21.9 KB
Line 
1#
2# CCGO_HMCPS.py
3#
4# Carry Code Generator Object using Hierarchical Merging Carry Pack Strategy
5#
6# Robert D. Cameron
7# November 26, 2012
8# Licensed under Open Software License 3.0
9#
10import ast
11import CCGO
12
13#
14# Helper functions
15#
16def TestHelper_Bitblock_Or(testExpr, bitBlockExpr):
17    if isinstance(testExpr, ast.Call):
18      assert isinstance(testExpr.func, ast.Name)
19      assert testExpr.func.id == 'bitblock::any'
20      testExpr.args[0] = make_call('simd_or', [bitBlockExpr, testExpr.args[0]])
21      return testExpr
22    else:
23      return ast.BinOp(testExpr, ast.BitOr(), make_call('bitblock::any', [bitBlockExpr]))
24
25def TestHelper_Integer_Or(testExpr, intExpr):
26    return ast.BinOp(testExpr, ast.BitOr(), intExpr)
27
28def mk_var(var, mode=ast.Load()):
29  if isinstance(var, str): 
30        var = ast.Name(var, mode)
31  return var
32 
33def make_assign(var, expr):
34   if isinstance(var, str): 
35        var = ast.Name(var, ast.Store())
36   return ast.Assign([var], expr)
37
38def make_index(var, num, mode=ast.Load()):
39  if isinstance(var, str): 
40        var = ast.Name(var, ast.Load())
41  return ast.Subscript(var, ast.Index(ast.Num(num)), mode)
42
43def make_index_store(var, num):
44  if isinstance(var, str): 
45        var = ast.Name(var, ast.Load())
46  return ast.Subscript(var, ast.Index(ast.Num(num)), ast.Store())
47
48def make_att(var, att, mode=ast.Load()):
49  if isinstance(var, str): 
50        var = ast.Name(var, ast.Load())
51  return ast.Attribute(var, att, mode)
52
53def make_att_store(var, att):
54  if isinstance(var, str): 
55        var = ast.Name(var, ast.Load())
56  return ast.Attribute(var, att, ast.Store())
57
58def make_call(fn_name, args):
59  if isinstance(fn_name, str): 
60        fn_name = ast.Name(fn_name, ast.Load())
61  return ast.Call(fn_name, args, [], None, None)
62
63def make_callStmt(fn_name, args):
64  if isinstance(fn_name, str): fn_name = ast.Name(fn_name, ast.Load())
65  return ast.Expr(ast.Call(fn_name, args, [], None, None))
66
67def make_mergeh(fw, x, y):
68  return make_call("esimd<%i>::mergeh" % fw, [mk_var(x), mk_var(y)])
69
70def make_zero(fw):
71  return make_call("simd<%i>::constant<0>" % fw, [])
72
73 
74#
75#
76# Carry Pack Assignment Strategy
77#
78# The hierarchical merging carry pack strategy packs carries
79# into packs of 2, 4, 8 and 16.   For example, to pack
80# 4 carries c0, c1, c2, and c3 into the 32-bit fields of
81# a 128-bit register, the following operations are used.
82#
83# c0 = pablo.SomeCarryGeneratingFn(...)
84# c1 = pablo.SomeCarryGeneratingFn(...)
85# c1_0 = esimd::mergeh<32>(c1, c0)
86# c2 = pablo.SomeCarryGeneratingFn(...)
87# c3 = pablo.SomeCarryGeneratingFn(...)
88# c3_2 = esimd::mergeh<32>(c3, c2)
89# c3_0 = esimd::mergeh<64>(c3_2, c1_0)
90#
91#
92# Packing operations are generated sequentially when
93# the appropriate individual carries or subpacks become
94# available.   
95#
96# Generate the packing operations assuming that the
97# carry_num carry has just been generated.
98#
99
100def pow2ceil(n):
101   c = 1
102   while c < n: c *= 2 
103   return c
104
105def pow2floor(n):
106   c = 1
107   while c <= n: c *= 2 
108   return c/2
109
110def low_bit(n):
111   return n - (n & (n-1))
112   
113def align(n, align_base):
114  return ((n + align_base - 1) / align_base) * align_base
115
116def determine_aligned_block_sizes(pack_size, cis, max_whiles_per_pack = 1, min_block_size = 1):
117  aligned_size = {}
118  for i in range(cis.block_count): aligned_size[i] = 0
119  seen = []
120  for i in range(cis.block_count):
121    # Work backwards to process all child blocks before the parent
122    # so that the parent incorporates the updated child counts.
123    b = cis.block_count - i - 1
124    b_carries = 0
125    op = cis.block_first_op[b]
126    while op < cis.block_first_op[b] + cis.block_op_count[b]:
127      sb = cis.containing_block[op]
128      if sb == b:
129        if op not in cis.advance_amount.keys(): b_carries += 1
130        elif cis.advance_amount[op] == 1: b_carries += 1
131        op += 1
132      else: 
133        align_base = aligned_size[sb]
134        if align_base > pack_size: align_base = pack_size
135        b_carries = align(b_carries, align_base)
136        b_carries += aligned_size[sb]
137        op += cis.block_op_count[sb]
138    #
139    # Align to min block size
140    aligned_size[b] = align(b_carries, min_block_size)
141    # Force whiles to use full packs; this possibly can be relaxed.
142    if cis.whileblock[b]:
143      aligned_size[b] = align(aligned_size[b], pack_size/max_whiles_per_pack)
144    if aligned_size[b] > pack_size:
145      aligned_size[b] = align(aligned_size[b], pack_size)
146    else:
147      aligned_size[b] = pow2ceil(aligned_size[b])
148  return aligned_size
149 
150MAX_LINE_LENGTH = 80
151
152def BitBlock_decls_from_vars(varlist):
153  global MAX_LINE_LENGTH
154  decls =  ""
155  if not len(varlist) == 0:
156          decls = "             BitBlock"
157          pending = ""
158          linelgth = 10
159          for v in varlist:
160            if linelgth + len(v) + 2 <= MAX_LINE_LENGTH:
161              decls += pending + " " + v
162              linelgth += len(pending + v) + 1
163            else:
164              decls += ";\n             BitBlock " + v
165              linelgth = 11 + len(v)
166            pending = ","
167          decls += ";"
168  return decls
169 
170def block_contains(b0, b1, parent_block_map):
171  if b0 == b1: return True
172  elif b1 == 0: return False
173  else: return block_contains(b0, parent_block_map[b1], parent_block_map)
174 
175class HMCPS_CCGO(CCGO.CCGO):
176    def __init__(self, BLOCK_SIZE, fw, carryInfoSet, carryPackVarName='carryG', temp_prefix='__c'):
177        self.BLOCK_SIZE = BLOCK_SIZE
178        self.fw = fw
179        self.field_count = self.BLOCK_SIZE/fw
180        self.carryInfoSet = carryInfoSet
181        self.carryPackVar = carryPackVarName
182        self.temp_prefix = temp_prefix
183
184    def allocate_all(self):
185        self.aligned_size = determine_aligned_block_sizes(self.field_count, self.carryInfoSet)
186        self.carryPack_count = (self.aligned_size[0] + self.field_count - 1) / self.field_count
187        self.totalPack_count = self.carryPack_count + self.carryInfoSet.adv_n_count
188        self.alloc_map = {}
189        self.alloc_map[0] = 0
190        self.adv_n_map = {}
191        self.block_base = {}
192        self.allocate_ops()
193        # carry_offset is used within the inner body of while loops to access local carries.
194        # The calculated (ub, rp) value is reduced by this amount for the local carry Pack(s).
195        self.carry_offset = 0
196#
197# Carry Storage/Access
198#
199# Carries are stored in one or more ubitblocks as byte values.
200# For each block, the carry count is rounded up to the nearest power of 2 ceiling P,
201# so that the carry test for that block is accessible as a single value of P bytes.
202# Packs of 1, 2, 4 or 8 carries are respectively represented
203# as one or more _8, _16, _32 or _64 values.  (Members of ubitblock union.)
204#
205#
206# Allocation phase determines the ubitblock_no and count for each block.
207
208#  carry-in access is a byte load  carryG[packno]._8[offset]
209#  carryout store is to a local pack var until we get to the final byte of a pack
210#
211#  if-test: let P be pack_size in {1,2,4,8,...}
212#    if P <= 8, use an integer test expression cG[packno]._%i % (P * 8)[block_offset]
213#     
214#  while test similar
215#    local while decl: use a copy of carryPack
216#    while finalize  carry combine:   round up and |= into structure
217#
218    def carry_pack_full(self, ub, v = None, mode = ast.Load()):
219       if v == None: v = self.carryPackVar
220       return make_att(make_index(v, ub), '_128', mode)
221
222    def carry_pack_index(self, fw, ub, rp, mode = ast.Load()):
223       return make_index(make_att(make_index(self.carryPackVar, ub), '_%i' % fw), rp, mode)
224
225    def local_pack_full(self, ub, mode = ast.Load()):
226       return self.carry_pack_full(ub, "sub" + self.carryPackVar, mode)
227
228    def local_pack_index(self, fw, ub, rp, mode = ast.Load()):
229       v = "sub" + self.carryPackVar
230       return make_index(make_att(make_index(v, ub), '_%i' % fw), rp, mode)
231 
232
233    def cg_temp(self, hi_carry, lo_carry = None):
234      if lo_carry == None or hi_carry == lo_carry: return "%s%i" % (self.temp_prefix, hi_carry)
235      else: return "%s%i_%i" % (self.temp_prefix, hi_carry, lo_carry)
236   
237    def local_temp(self, hi_carry, lo_carry = None):
238      if lo_carry == None or hi_carry == lo_carry: return "sub%s%i" % (self.temp_prefix, hi_carry)
239      else: return "sub%s%i_%i" % (self.temp_prefix, hi_carry, lo_carry)
240   
241    def gen_merges(self, carry_last, carry_base):
242      size = carry_last - carry_base + 1
243      if carry_last & size: 
244        v1 = mk_var(self.cg_temp(carry_last, carry_base))
245        v0 = mk_var(self.cg_temp(carry_last - size, carry_base - size))
246        v2 = mk_var(self.cg_temp(carry_last, carry_base - size), ast.Store())
247        return [make_assign(v2, make_mergeh(self.fw * size, v1, v0))] + self.gen_merges(carry_last, carry_base - size)
248      else: return []
249
250    #
251    #  Given that carry_num carries have been generated and packed,
252    #  add zero_count additional carry zero values and pack.
253    #  Use shifts to introduce multiple zeroes, where possible.
254    #
255    def gen_multiple_carry_zero_then_pack(self, carry_num, zero_count):
256      if zero_count == 0: return []
257      pending_carry_pack_size = low_bit(carry_num)
258      pending_carry_base = carry_num - pending_carry_pack_size
259      # We may be able to fill zeroes by shifting.
260      # But the shift is limited by any further pending carry pack and
261      # the constraint that the result must produce a well-formed pack
262      # having a power-of-2 entries.
263      #
264      final_num = carry_num + zero_count
265      pack_size2 = low_bit(pending_carry_base)
266      if pending_carry_base == 0:
267        shift = pow2floor(final_num) - pending_carry_pack_size
268      else:
269        shift = min(low_bit(pending_carry_base), low_bit(final_num)) - pending_carry_pack_size
270      if pending_carry_pack_size == 0 or shift == 0:
271        # There is either no pending pack or we are not generating enough
272        # carry zeroes to combine into the pending pack, so we can only add new
273        # packs.
274        #
275        if zero_count == 1:  return [make_assign(self.cg_temp(carry_num), make_zero(self.fw))]
276        else: 
277          zero_count_floor = pow2floor(zero_count)
278          hi_num = carry_num + zero_count_floor
279          a1 = make_assign(self.cg_temp(hi_num - 1, carry_num), make_zero(self.fw))
280          remaining_zeroes = zero_count - zero_count_floor
281          return [a1] + self.gen_multiple_carry_zero_then_pack(hi_num, remaining_zeroes) 
282      #
283      shift_result = self.cg_temp(carry_num + shift - 1, pending_carry_base)
284      pending = self.cg_temp(carry_num - 1, pending_carry_base)
285      #a1 = make_assign(shift_result, make_call('bitblock::srli<%i>' % (self.fw * shift), [mk_var(pending)]))
286      a1 = make_assign(shift_result, make_call('mvmd<%i>::srli<%i>' % (self.fw, shift), [mk_var(pending)]))
287      # Do any necessary merges
288      m = self.gen_merges(carry_num + shift - 1,  pending_carry_base)
289      return [a1] + m + self.gen_multiple_carry_zero_then_pack(carry_num + shift, zero_count - shift)
290
291
292    def allocate_ops(self):
293      carry_count = 0
294      adv_n_count = 0
295      for op in range(self.carryInfoSet.operation_count):
296        b = self.carryInfoSet.containing_block[op]
297        if op != 0: 
298          # If we've just left a block, ensure that we are aligned.
299          b_last = self.carryInfoSet.containing_block[op-1]
300          if not block_contains(b_last, b, self.carryInfoSet.parent_block):
301            # find the max-sized block just exited.
302            while not block_contains(self.carryInfoSet.parent_block[b_last], b, self.carryInfoSet.parent_block):
303              b_last = self.carryInfoSet.parent_block[b_last]
304            align_base = self.aligned_size[b_last]
305            if align_base > self.field_count: align_base = self.field_count
306            carry_count = align(carry_count, align_base)         
307        if self.carryInfoSet.block_first_op[b] == op:
308          # If we're just entering a block, ensure that we are aligned.
309          align_base = self.aligned_size[b]
310          if align_base > self.field_count: align_base = self.field_count
311          carry_count = align(carry_count, align_base)
312        if op not in self.carryInfoSet.advance_amount.keys():
313          self.alloc_map[op] = carry_count
314          carry_count += 1
315        elif self.carryInfoSet.advance_amount[op] == 1: 
316          self.alloc_map[op] = carry_count
317          carry_count += 1
318        else:
319          # Advance_n op, carry_count does not change.
320          self.alloc_map[op] = carry_count
321          self.adv_n_map[op] = adv_n_count
322          adv_n_count += 1
323      # When processing the last operation, make sure that the "next" operation
324      # appears to start a new pack.
325      self.alloc_map[self.carryInfoSet.operation_count] = align(carry_count, self.field_count)
326      for b in range(self.carryInfoSet.block_count): 
327         self.block_base[b] = self.alloc_map[self.carryInfoSet.block_first_op[b]]
328     
329    def GenerateCarryDecls(self):
330        return "  ubitblock %s [%i];\n" % (self.carryPackVar, self.totalPack_count)
331    def GenerateInitializations(self):
332        v = self.carryPackVar       
333        inits = ""
334        for i in range(0, self.totalPack_count):
335          inits += "%s[%i]._128 = simd<%i>::constant<0>();\n" % (v, i, self.fw)
336        for op_no in range(self.carryInfoSet.block_op_count[0]):
337          if op_no in self.carryInfoSet.init_one_list: 
338            posn = self.alloc_map[op_no]
339            ub = posn/self.field_count
340            rp = posn%self.field_count
341            inits += "%s[%i]._%i[%i] = 1;\n" % (self.carryPackVar, ub, self.fw, rp)
342        return inits
343    def GenerateStreamFunctionDecls(self):
344        f = self.field_count
345        s = 1
346        decls = []
347        while f > 0:
348          decls += [self.cg_temp(s*(i+1)-1, s*i) for i in range(f)]
349          f = f/2
350          s = s * 2
351        return BitBlock_decls_from_vars(decls)
352
353    def GenerateCarryInAccess(self, operation_no):
354        block_no = self.carryInfoSet.containing_block[operation_no]
355        posn = self.alloc_map[operation_no] - self.carry_offset
356        ub = posn/self.field_count
357        rp = posn%self.field_count
358        return make_call("convert", [self.carry_pack_index(self.fw, ub, rp)])
359    def GenerateCarryOutStore(self, operation_no, carry_out_expr):
360        block_no = self.carryInfoSet.containing_block[operation_no]
361        posn = self.alloc_map[operation_no] - self.carry_offset
362        ub = posn/self.field_count
363        rp = posn%self.field_count
364        # Save the carry in the carry temp variable and then merge
365        # pending carry temps as far as possible.
366        assigs = [make_assign(self.temp_prefix + repr(rp), carry_out_expr)] 
367        assigs += self.gen_merges(rp, rp)
368        # Only generate an actual store for the last carryout in a pack.
369        next_op = operation_no + 1
370        while self.adv_n_map.has_key(next_op): next_op += 1
371        next_posn = self.alloc_map[next_op] - self.carry_offset
372        skip = next_posn - posn - 1
373        if skip > 0: 
374          assigs += self.gen_multiple_carry_zero_then_pack(rp+1, skip)
375        if next_posn % self.field_count == 0:
376          shift_op = "simd<%i>::srli<%i>" % (self.fw, self.fw-1)
377          storable_carry_in_form = make_call(shift_op, [mk_var(self.cg_temp(self.field_count - 1, 0))])
378          assigs.append(make_assign(self.carry_pack_full(ub, mode = ast.Store()), storable_carry_in_form))
379        return assigs
380    def GenerateAdvanceInAccess(self, operation_no):
381        return self.carry_pack_full(self.carryPack_count + self.adv_n_map[operation_no])
382    def GenerateAdvanceOutStore(self, operation_no, adv_out_expr):
383        return [ast.Assign([self.carry_pack_full(self.carryPack_count + self.adv_n_map[operation_no], mode=ast.Store())], 
384                           make_call("bitblock::srli<64>", [adv_out_expr]))]
385    def GenerateTestAll(self, instance_name):
386        if self.totalPack_count == 0: return ast.Num(0)
387        else:
388            v = make_att(instance_name, self.carryPackVar)
389            t = self.carry_pack_full(0, v)
390            for i in range(1, self.totalPack_count): 
391              t2 = self.carry_pack_full(i, v)
392              t = make_call('simd_or', [t, t2])
393            return make_call('bitblock::any', [t])
394    def GenerateTest(self, block_no, testExpr):
395        posn = self.block_base[block_no] - self.carry_offset
396        ub = posn/self.field_count
397        rp = posn%self.field_count
398        count = self.aligned_size[block_no] 
399        width = count * self.fw
400        if count < self.field_count:
401            t = self.carry_pack_index(width, ub, rp/count)
402            return TestHelper_Integer_Or(testExpr, t)
403        else:
404            t = self.carry_pack_full(ub)
405            for i in range(1, count/self.field_count): 
406              v2 = self.carry_pack_full(ub + i)
407              t = make_call('simd_or', [t, v2])
408            return TestHelper_Bitblock_Or(testExpr, t)
409    def GenerateCarryIfTest(self, block_no, ifTest):
410        return self.GenerateTest(block_no, ifTest)
411
412    def GenerateCarryElseFinalization(self, block_no):
413        # if the block consists of full carry packs, then
414        # no action need be taken: the corresponding carry-in packs
415        # must already be zero, or the then branch would have been taken.
416        count = self.aligned_size[block_no]
417        if count % self.field_count == 0: return []
418        # The block has half a carry-pack or less.
419        assigs = []
420        posn = self.block_base[block_no] - self.carry_offset
421        ub = posn / self.field_count
422        rp = posn % self.field_count
423        next_op = self.carryInfoSet.block_first_op[block_no] + self.carryInfoSet.block_op_count[block_no]
424        end_pos = (self.alloc_map[next_op]  - self.carry_offset - 1) % self.field_count
425        assigs = self.gen_multiple_carry_zero_then_pack(rp, end_pos - rp + 1)
426        if (end_pos + 1) % self.field_count == 0:
427          shift_op = "simd<%i>::srli<%i>" % (self.fw, self.fw-1)
428          storable_carry_in_form = make_call(shift_op, [mk_var(self.cg_temp(self.field_count - 1, 0))])
429          assigs.append(make_assign(self.carry_pack_full(ub, mode = ast.Store()), storable_carry_in_form))
430        return assigs
431
432    def GenerateLocalDeclare(self, block_no):
433        if self.carryInfoSet.block_op_count[block_no] == 0: return []
434        count = self.aligned_size[block_no] 
435        if count >= self.field_count:
436          ub_count = count / self.field_count
437          decls = [make_callStmt('ubitblock_declare', [mk_var('sub' + self.carryPackVar), ast.Num(ub_count)])]
438          count = self.field_count
439        else: decls = []
440        # Generate carry pack temps.
441        f = count
442        s = 1
443        temps = []
444        while f > 0:
445          temps += [self.local_temp(s*(i+1)-1, s*i) for i in range(f)]
446          f = f/2
447          s = s * 2
448        #return BitBlock_decls_from_vars(decls)
449        return decls + [make_callStmt('BitBlock_declare', [mk_var(t)]) for t in temps]
450   
451    def GenerateCarryWhileTest(self, block_no, testExpr):
452        return self.GenerateTest(block_no, testExpr)
453
454    def EnterLocalWhileBlock(self, operation_offset): 
455        self.carryPackVar = "sub" + self.carryPackVar
456        self.temp_prefix = "sub" + self.temp_prefix
457        self.carry_offset = self.alloc_map[operation_offset]
458
459    def ExitLocalWhileBlock(self): 
460        self.carryPackVar = self.carryPackVar[3:]
461        self.temp_prefix = self.temp_prefix[3:]
462        self.carry_offset = 0
463       
464    def GenerateCarryWhileFinalization(self, block_no):
465        posn = self.block_base[block_no]
466        ub = posn/self.field_count
467        rp = posn%self.field_count
468        count = self.aligned_size[block_no] 
469        if count < self.field_count:
470          v0 = self.cg_temp(rp + count - 1, rp)
471          lv0 = self.local_temp(count - 1, 0)
472          return [make_assign(v0, make_call('simd_or', [mk_var(v0), mk_var(lv0)]))]
473        n = (count+self.field_count-1)/self.field_count
474        assigs = []
475        for i in range(n):
476          assigs.append(make_assign(self.carry_pack_full(ub + i, mode = ast.Store()), make_call('simd_or', [self.carry_pack_full(ub + i), self.local_pack_full(i)])))
477        return assigs
478    def GenerateStreamFunctionFinalization(self):
479        return []
480
481#
482#  A version of HMCPS_CCGO eliminating use of "convert"
483#
484class HMCPS_CCGO2(HMCPS_CCGO):
485
486
487    def GenerateCarryInAccess(self, operation_no):
488        block_no = self.carryInfoSet.containing_block[operation_no]
489        posn = self.alloc_map[operation_no] - self.carry_offset
490        ub = posn/self.field_count
491        rp = posn%self.field_count
492        #return make_call("convert", [self.carry_pack_index(self.fw, ub, rp)])
493        if rp == 0: e = self.carry_pack_full(ub)
494        else: e = make_call("mvmd<%i>::srli<%i>" %(self.fw, rp), [self.carry_pack_full(ub)])
495        if rp == self.field_count - 1:
496          return e
497        else: return make_call('simd_and', [e, mk_var("simd_const_1")])
498
499#
500#  Eliminating ubitblock
501#
502class HMCPS_CCGO3(HMCPS_CCGO2):
503
504    def carry_pack_full(self, ub, v = None, mode = ast.Load()):
505       if v == None: v = self.carryPackVar
506       return make_index(v, ub, mode)
507
508    def carry_pack_index(self, fw, ub, rp, mode = ast.Load()):
509       return make_call("mvmd<%i>::extract<%i>" % (fw, rp), [self.carry_pack_full(ub)])
510
511    def GenerateCarryDecls(self):
512        return "  BitBlock %s [%i];\n" % (self.carryPackVar, self.totalPack_count)
513
514    def GenerateInitializations(self):
515        v = self.carryPackVar       
516        inits = ""
517        for i in range(0, self.totalPack_count):
518          inits += "%s[%i] = simd<%i>::constant<0>();\n" % (v, i, self.fw)
519        for op_no in range(self.carryInfoSet.block_op_count[0]):
520          if op_no in self.carryInfoSet.init_one_list: 
521            posn = self.alloc_map[op_no]
522            ub = posn/self.field_count
523            rp = posn%self.field_count
524            v = "%s[%i]" % (self.carryPackVar, ub)
525            inits += "%s = simd_or(%s, mvmd<%i>::slli<%i>(simd_const_1)) ;\n" % (v, v, self.fw, rp)
526        return inits
527
528    def GenerateLocalDeclare(self, block_no):
529        if self.carryInfoSet.block_op_count[block_no] == 0: return []
530        count = self.aligned_size[block_no] 
531        if count >= self.field_count:
532          ub_count = count / self.field_count
533          decls = [make_callStmt('BitBlock_declare', [self.local_pack_full(ub_count)])]
534          decls += [make_assign(self.local_pack_full(i, ast.Store()), make_zero(self.fw)) for i in range(ub_count)]
535          count = self.field_count
536        else: decls = []
537        # Generate carry pack temps.
538        f = count
539        s = 1
540        temps = []
541        while f > 0:
542          temps += [self.local_temp(s*(i+1)-1, s*i) for i in range(f)]
543          f = f/2
544          s = s * 2
545        #return BitBlock_decls_from_vars(decls)
546        return decls + [make_callStmt('BitBlock_declare', [mk_var(t)]) for t in temps]
547
Note: See TracBrowser for help on using the repository browser.