| 1 | # |
|---|
| 2 | # Pablo.py - parallel bitstream to bitblock |
|---|
| 3 | # 2nd generation compiler |
|---|
| 4 | # |
|---|
| 5 | # Copyright 2010, 2011, Robert D. Cameron, Kenneth S. Herdy |
|---|
| 6 | # All rights reserved. |
|---|
| 7 | # |
|---|
| 8 | import ast, copy, sys |
|---|
| 9 | import Cgen |
|---|
| 10 | |
|---|
| 11 | name_substitution_map = {} |
|---|
| 12 | do_block_inline_decorator = 'IDISA_INLINE ' |
|---|
| 13 | do_final_block_inline_decorator = '' |
|---|
| 14 | error_routine = 'raise_assert' |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | def is_BuiltIn_Call(fncall, builtin_fnname, builtin_arg_cnt, builtin_fnmod_noprefix='pablo'): |
|---|
| 18 | if isinstance(fncall.func, ast.Name): iscall = fncall.func.id == builtin_fnname |
|---|
| 19 | elif isinstance(fncall.func, ast.Attribute) and isinstance(fncall.func.value, ast.Name): |
|---|
| 20 | iscall = fncall.func.value.id == builtin_fnmod_noprefix and fncall.func.attr == builtin_fnname |
|---|
| 21 | return iscall and len(fncall.args) == builtin_arg_cnt |
|---|
| 22 | |
|---|
| 23 | def dump_Call(fncall): |
|---|
| 24 | if isinstance(fncall.func, ast.Name): print "fn_name = %s\n" % fncall.func.id |
|---|
| 25 | elif isinstance(fncall.func, ast.Attribute) and isinstance(fncall.func.value, ast.Name): |
|---|
| 26 | print "fn_name = %s.%s\n" % (fncall.func.value.id, fncall.func.attr) |
|---|
| 27 | print "len(fncall.args) = %s\n" % len(fncall.args) |
|---|
| 28 | |
|---|
| 29 | def is_simd_not(e): |
|---|
| 30 | return isinstance(e, ast.Call) and isinstance(e.func, ast.Name) and e.func.id == 'simd_not' |
|---|
| 31 | |
|---|
| 32 | def mkQname(obj, field): |
|---|
| 33 | return ast.Attribute(ast.Name(obj, ast.Load()), field, ast.Load()) |
|---|
| 34 | |
|---|
| 35 | def mkCall(fn_name, args): |
|---|
| 36 | if isinstance(fn_name, str): |
|---|
| 37 | if name_substitution_map.has_key(fn_name): fn_name = name_substitution_map[fn_name] |
|---|
| 38 | fn_name = ast.Name(fn_name, ast.Load()) |
|---|
| 39 | return ast.Call(fn_name, args, [], None, None) |
|---|
| 40 | |
|---|
| 41 | def mkCallStmt(fn_name, args): |
|---|
| 42 | if isinstance(fn_name, str): fn_name = ast.Name(fn_name, ast.Load()) |
|---|
| 43 | return ast.Expr(ast.Call(fn_name, args, [], None, None)) |
|---|
| 44 | |
|---|
| 45 | # |
|---|
| 46 | # Reducing AugAssign, e.g. x |= y becomes x = x | y |
|---|
| 47 | # |
|---|
| 48 | class AugAssignRemoval(ast.NodeTransformer): |
|---|
| 49 | def xfrm(self, t): |
|---|
| 50 | return self.generic_visit(t) |
|---|
| 51 | def visit_AugAssign(self, e): |
|---|
| 52 | self.generic_visit(e) |
|---|
| 53 | return ast.Assign([e.target], ast.BinOp(e.target, e.op, e.value)) |
|---|
| 54 | # |
|---|
| 55 | # pablo.Advance(pablo.Advance(x, n)) => pablo.Advance(x, n+1) |
|---|
| 56 | # |
|---|
| 57 | class AdvanceCombiner(ast.NodeTransformer): |
|---|
| 58 | def xfrm(self, t): |
|---|
| 59 | return self.generic_visit(t) |
|---|
| 60 | def visit_if(self, ifNode): |
|---|
| 61 | return IfNode |
|---|
| 62 | def visit_While(self, whileNode): |
|---|
| 63 | return whileNode |
|---|
| 64 | def visit_Call(self, callnode): |
|---|
| 65 | self.generic_visit(callnode) |
|---|
| 66 | if len(callnode.args) == 0: return callnode |
|---|
| 67 | if not isinstance(callnode.args[0], ast.Call): return callnode |
|---|
| 68 | if is_BuiltIn_Call(callnode,'Advance', 1): |
|---|
| 69 | if is_BuiltIn_Call(callnode.args[0],'Advance', 1): |
|---|
| 70 | callnode.args = [callnode.args[0].args[0], ast.Num(2)] |
|---|
| 71 | elif is_BuiltIn_Call(callnode.args[0], 'Advance', 2): |
|---|
| 72 | if isinstance(callnode.args[0].args[1], ast.Num): |
|---|
| 73 | callnode.args = [callnode.args[0].args[0], ast.Num(callnode.args[0].args[1].n + 1)] |
|---|
| 74 | else: |
|---|
| 75 | callnode.args = [callnode.args[0].args[0], ast.BinOp(callnode.args[0].args[1], ast.Add(), ast.Num(1))] |
|---|
| 76 | return callnode |
|---|
| 77 | |
|---|
| 78 | |
|---|
| 79 | # |
|---|
| 80 | # Translating pablo.match(marker, str) |
|---|
| 81 | # Incremental character match with lookahead |
|---|
| 82 | # |
|---|
| 83 | CharNameMap = {'[' : 'LBrak', ']' : 'RBrak', '{' : 'LBrace', '}' : 'LBrace', '(' : 'LParen', ')' : 'RParen', \ |
|---|
| 84 | '!' : 'Exclam', '"' : 'DQuote', '#' : 'Hash', '$' : 'Dollar', '%' : 'PerCent', '&': 'RefStart', \ |
|---|
| 85 | "'" : 'SQuote', '*': 'Star', '+' : 'Plus', ',' : 'Comma', '-' : 'Hyphen', '.' : 'Dot', '/' : 'Slash', \ |
|---|
| 86 | ':' : 'Colon', ';' : 'Semicolon', '=' : 'Equals', '?' : 'QMark', '@' : 'AtSign', '\\' : 'BackSlash', \ |
|---|
| 87 | '^' : 'Caret', '_' : 'Underscore', '|' : 'VBar', '~' : 'Tilde', ' ' : 'SP', '\t' : 'HT', '\m' : 'CR', '\n' : 'LF'} |
|---|
| 88 | |
|---|
| 89 | def GetCharName(char): |
|---|
| 90 | if char >= 'a' and char <= 'z' or char >= 'A' and char <= 'Z': return 'letter_' + char |
|---|
| 91 | elif char >= '0' and char <= '9': return 'digit_' + char |
|---|
| 92 | else: return CharNameMap[char] |
|---|
| 93 | |
|---|
| 94 | def MkCharStream(char): |
|---|
| 95 | return mkQname('lex', GetCharName(char)) |
|---|
| 96 | |
|---|
| 97 | def MkLookAheadExpr(v, i): |
|---|
| 98 | return mkCall(mkQname('pablo', 'LookAhead'), [v, ast.Num(i)]) |
|---|
| 99 | |
|---|
| 100 | def CompileMatch(match_var, string_to_match): |
|---|
| 101 | expr = mkCall('simd_and', [match_var, MkCharStream(string_to_match[0])]) |
|---|
| 102 | for i in range(1, len(string_to_match)): |
|---|
| 103 | expr = mkCall('simd_and', [expr, MkLookAheadExpr(MkCharStream(string_to_match[i]), i)]) |
|---|
| 104 | return expr |
|---|
| 105 | |
|---|
| 106 | class StringMatchCompiler(ast.NodeTransformer): |
|---|
| 107 | def xfrm(self, t): |
|---|
| 108 | return self.generic_visit(t) |
|---|
| 109 | def visit_Call(self, callnode): |
|---|
| 110 | if is_BuiltIn_Call(callnode,'match', 2): |
|---|
| 111 | ast.dump(callnode) |
|---|
| 112 | assert isinstance(callnode.args[0], ast.Str) |
|---|
| 113 | string_to_match = callnode.args[0].s |
|---|
| 114 | match_var = callnode.args[1] |
|---|
| 115 | expr = mkCall('simd_and', [match_var, MkCharStream(string_to_match[0])]) |
|---|
| 116 | for i in range(1, len(string_to_match)): |
|---|
| 117 | expr = mkCall('simd_and', [expr, MkLookAheadExpr(MkCharStream(string_to_match[i]), i)]) |
|---|
| 118 | return expr |
|---|
| 119 | else: return callnode |
|---|
| 120 | |
|---|
| 121 | |
|---|
| 122 | |
|---|
| 123 | # |
|---|
| 124 | # Introducing BitBlock logical operations |
|---|
| 125 | # |
|---|
| 126 | class Bitwise_to_SIMD(ast.NodeTransformer): |
|---|
| 127 | """ |
|---|
| 128 | Make the following substitutions: |
|---|
| 129 | x & y => simd_and(x, y) |
|---|
| 130 | x & ~y => simd_andc(x, y) |
|---|
| 131 | x | y => simd_or(x, y) |
|---|
| 132 | x ^ y => simd_xor(x, y) |
|---|
| 133 | ~x => simd_not(x) |
|---|
| 134 | 0 => simd_const_1(0) |
|---|
| 135 | -1 => simd_const_1(1) |
|---|
| 136 | if x: => if bitblock::any(x): |
|---|
| 137 | while x: => while bitblock::any(x): |
|---|
| 138 | >>> ast_show(Bitwise_to_SIMD().xfrm(ast.parse("pfx = bit0 & bit1; sfx = bit0 &~ bit1"))) |
|---|
| 139 | |
|---|
| 140 | pfx = simd_and(bit0, bit1) |
|---|
| 141 | sfx = simd_and(bit0, simd_not(bit1)) |
|---|
| 142 | >>> |
|---|
| 143 | """ |
|---|
| 144 | def xfrm(self, t): |
|---|
| 145 | return self.generic_visit(t) |
|---|
| 146 | def visit_UnaryOp(self, t): |
|---|
| 147 | self.generic_visit(t) |
|---|
| 148 | if isinstance(t.op, ast.Invert): |
|---|
| 149 | return mkCall('simd_not', [t.operand]) |
|---|
| 150 | else: return t |
|---|
| 151 | def visit_BinOp(self, t): |
|---|
| 152 | self.generic_visit(t) |
|---|
| 153 | if isinstance(t.op, ast.BitOr): |
|---|
| 154 | return mkCall('simd_or', [t.left, t.right]) |
|---|
| 155 | elif isinstance(t.op, ast.BitAnd): |
|---|
| 156 | if is_simd_not(t.right): return mkCall('simd_andc', [t.left, t.right.args[0]]) |
|---|
| 157 | elif is_simd_not(t.left): return mkCall('simd_andc', [t.right, t.left.args[0]]) |
|---|
| 158 | else: return mkCall('simd_and', [t.left, t.right]) |
|---|
| 159 | elif isinstance(t.op, ast.BitXor): |
|---|
| 160 | return mkCall('simd_xor', [t.left, t.right]) |
|---|
| 161 | else: return t |
|---|
| 162 | def visit_Num(self, numnode): |
|---|
| 163 | n = numnode.n |
|---|
| 164 | if n == 0: return mkCall('simd<1>::constant<0>', []) |
|---|
| 165 | elif n == -1: return mkCall('simd<1>::constant<1>', []) |
|---|
| 166 | else: return numnode |
|---|
| 167 | def visit_If(self, ifNode): |
|---|
| 168 | self.generic_visit(ifNode) |
|---|
| 169 | ifNode.test = mkCall('bitblock::any', [ifNode.test]) |
|---|
| 170 | return ifNode |
|---|
| 171 | def visit_While(self, whileNode): |
|---|
| 172 | self.generic_visit(whileNode) |
|---|
| 173 | whileNode.test = mkCall('bitblock::any', [whileNode.test]) |
|---|
| 174 | return whileNode |
|---|
| 175 | def visit_Subscript(self, numnode): |
|---|
| 176 | return numnode # no recursive modifications of index expressions |
|---|
| 177 | |
|---|
| 178 | # |
|---|
| 179 | # Generating BitBlock declarations for Local Variables |
|---|
| 180 | # |
|---|
| 181 | class FunctionVars(ast.NodeVisitor): |
|---|
| 182 | def __init__(self,node): |
|---|
| 183 | self.params = [] |
|---|
| 184 | self.stores = [] |
|---|
| 185 | self.generic_visit(node) |
|---|
| 186 | def visit_Name(self, nm): |
|---|
| 187 | if isinstance(nm.ctx, ast.Param): |
|---|
| 188 | self.params.append(nm.id) |
|---|
| 189 | if isinstance(nm.ctx, ast.Store): |
|---|
| 190 | if nm.id not in self.stores: self.stores.append(nm.id) |
|---|
| 191 | def getLocals(self): |
|---|
| 192 | return [v for v in self.stores if not v in self.params] |
|---|
| 193 | |
|---|
| 194 | MAX_LINE_LENGTH = 80 |
|---|
| 195 | |
|---|
| 196 | def BitBlock_decls_from_vars(varlist): |
|---|
| 197 | global MAX_LINE_LENGTH |
|---|
| 198 | decls = "" |
|---|
| 199 | if not len(varlist) == 0: |
|---|
| 200 | decls = " BitBlock" |
|---|
| 201 | pending = "" |
|---|
| 202 | linelgth = 10 |
|---|
| 203 | for v in varlist: |
|---|
| 204 | if linelgth + len(v) + 2 <= MAX_LINE_LENGTH: |
|---|
| 205 | decls += pending + " " + v |
|---|
| 206 | linelgth += len(pending + v) + 1 |
|---|
| 207 | else: |
|---|
| 208 | decls += ";\n BitBlock " + v |
|---|
| 209 | linelgth = 11 + len(v) |
|---|
| 210 | pending = "," |
|---|
| 211 | decls += ";" |
|---|
| 212 | return decls |
|---|
| 213 | |
|---|
| 214 | def BitBlock_decls_of_fn(fndef): |
|---|
| 215 | return BitBlock_decls_from_vars(FunctionVars(fndef).getLocals()) |
|---|
| 216 | |
|---|
| 217 | def BitBlock_header_of_fn(fndef): |
|---|
| 218 | Ccode = "static inline void " + fndef.name + "(" |
|---|
| 219 | pending = "" |
|---|
| 220 | for arg in fndef.args.args: |
|---|
| 221 | if isinstance(arg, ast.Name): |
|---|
| 222 | Ccode += pending + arg.id.upper()[0] + arg.id[1:] + " & " + arg.id |
|---|
| 223 | pending = ", " |
|---|
| 224 | if CarryCounter().count(fndef) > 0: |
|---|
| 225 | Ccode += pending + " CarryQtype & carryQ" |
|---|
| 226 | Ccode += ")" |
|---|
| 227 | return Ccode |
|---|
| 228 | |
|---|
| 229 | |
|---|
| 230 | |
|---|
| 231 | # |
|---|
| 232 | # Stream Initialization Statement Extraction |
|---|
| 233 | # |
|---|
| 234 | # streamvar = 1 ==> streamvar = sisd_from_int(1) initially. |
|---|
| 235 | class StreamInitializations(ast.NodeTransformer): |
|---|
| 236 | def xfrm(self, node): |
|---|
| 237 | self.stream_stmts = [] |
|---|
| 238 | self.loop_post_inits = [] |
|---|
| 239 | self.generic_visit(node) |
|---|
| 240 | return Cgen.py2C().gen(self.stream_stmts) |
|---|
| 241 | def visit_Assign(self, node): |
|---|
| 242 | if isinstance(node.value, ast.Num): |
|---|
| 243 | if node.value.n == 0: return node |
|---|
| 244 | elif node.value.n == -1: return node |
|---|
| 245 | else: |
|---|
| 246 | stream_init = copy.deepcopy(node) |
|---|
| 247 | stream_init.value = mkCall('sisd_from_int', [node.value]) |
|---|
| 248 | loop_init = copy.deepcopy(node) |
|---|
| 249 | loop_init.value.n = 0 |
|---|
| 250 | self.stream_stmts.append(stream_init) |
|---|
| 251 | self.loop_post_inits.append(loop_init) |
|---|
| 252 | return None |
|---|
| 253 | else: return node |
|---|
| 254 | def visit_FunctionDef(self, node): |
|---|
| 255 | self.generic_visit(node) |
|---|
| 256 | node.body = node.body + self.loop_post_inits |
|---|
| 257 | return node |
|---|
| 258 | |
|---|
| 259 | |
|---|
| 260 | |
|---|
| 261 | # |
|---|
| 262 | # Carry Introduction Transformation |
|---|
| 263 | # |
|---|
| 264 | class CarryCounter(ast.NodeVisitor): |
|---|
| 265 | def visit_Call(self, callnode): |
|---|
| 266 | self.generic_visit(callnode) |
|---|
| 267 | if is_BuiltIn_Call(callnode,'Advance', 1) or is_BuiltIn_Call(callnode,'ScanThru', 2) or is_BuiltIn_Call(callnode,'ScanTo', 2) or is_BuiltIn_Call(callnode,'ScanToFirst', 1) or is_BuiltIn_Call(callnode,'AdvanceThenScanThru', 2) or is_BuiltIn_Call(callnode,'AdvanceThenScanTo', 2) or is_BuiltIn_Call(callnode,'SpanUpTo', 2) or is_BuiltIn_Call(callnode,'InclusiveSpan', 2) or is_BuiltIn_Call(callnode,'ExclusiveSpan', 2): |
|---|
| 268 | self.carry_count += 1 |
|---|
| 269 | def visit_BinOp(self, exprnode): |
|---|
| 270 | self.generic_visit(exprnode) |
|---|
| 271 | if isinstance(exprnode.op, ast.Sub): |
|---|
| 272 | self.carry_count += 1 |
|---|
| 273 | if isinstance(exprnode.op, ast.Add): |
|---|
| 274 | self.carry_count += 1 |
|---|
| 275 | def count(self, nodeToVisit): |
|---|
| 276 | self.carry_count = 0 |
|---|
| 277 | self.generic_visit(nodeToVisit) |
|---|
| 278 | return self.carry_count |
|---|
| 279 | |
|---|
| 280 | class adv_nCounter(ast.NodeVisitor): |
|---|
| 281 | def visit_Call(self, callnode): |
|---|
| 282 | self.generic_visit(callnode) |
|---|
| 283 | if is_BuiltIn_Call(callnode,'Advance32', 1): |
|---|
| 284 | self.adv_n_count += 1 |
|---|
| 285 | if is_BuiltIn_Call(callnode,'Advance', 2): |
|---|
| 286 | self.adv_n_count += 1 |
|---|
| 287 | def count(self, nodeToVisit): |
|---|
| 288 | self.adv_n_count = 0 |
|---|
| 289 | self.generic_visit(nodeToVisit) |
|---|
| 290 | return self.adv_n_count |
|---|
| 291 | |
|---|
| 292 | class CarryIntro(ast.NodeTransformer): |
|---|
| 293 | def __init__(self, carryvar="carryQ", carryin = "_ci", carryout = "_co"): |
|---|
| 294 | self.carryvar = ast.Name(carryvar, ast.Load()) |
|---|
| 295 | self.carryin = carryin |
|---|
| 296 | self.carryout = carryout |
|---|
| 297 | def xfrm_fndef(self, fndef): |
|---|
| 298 | self.current_carry = 0 |
|---|
| 299 | self.current_adv_n = 0 |
|---|
| 300 | carry_count = CarryCounter().count(fndef) |
|---|
| 301 | if carry_count == 0: return fndef |
|---|
| 302 | self.generic_visit(fndef) |
|---|
| 303 | # |
|---|
| 304 | # fndef.body.insert(0, mkCallStmt('CarryDeclare', [self.carryvar, ast.Num(carry_count)])) |
|---|
| 305 | return fndef |
|---|
| 306 | def generic_xfrm(self, node): |
|---|
| 307 | self.current_carry = 0 |
|---|
| 308 | self.current_adv_n = 0 |
|---|
| 309 | carry_count = CarryCounter().count(node) |
|---|
| 310 | adv_n_count = adv_nCounter().count(node) |
|---|
| 311 | if carry_count == 0 and adv_n_count == 0: return node |
|---|
| 312 | self.generic_visit(node) |
|---|
| 313 | return node |
|---|
| 314 | def visit_Call(self, callnode): |
|---|
| 315 | self.generic_visit(callnode) |
|---|
| 316 | #CARRYSET |
|---|
| 317 | #carry_args = [ast.Num(self.current_carry)] |
|---|
| 318 | #adv_n_args = [ast.Subscript(ast.Name(self.carryvar.id + '.pending64', ast.Load()), ast.Num(self.current_adv_n), ast.Load())] |
|---|
| 319 | adv_n_pending = ast.Subscript(ast.Name(self.carryvar.id + '.pending64', ast.Load()), ast.Num(self.current_adv_n), ast.Load()) |
|---|
| 320 | if self.carryin == "_ci": |
|---|
| 321 | carry_args = [mkCall(self.carryvar.id + "." + 'get_carry_in', [ast.Num(self.current_carry)]), ast.Num(self.current_carry)] |
|---|
| 322 | adv_n_args = [adv_n_pending, ast.Num(self.current_adv_n)] |
|---|
| 323 | else: |
|---|
| 324 | carry_args = [mkCall('simd<1>::constant<0>', []), ast.Num(self.current_carry)] |
|---|
| 325 | adv_n_args = [mkCall('simd<1>::constant<0>', []), ast.Num(self.current_adv_n)] |
|---|
| 326 | |
|---|
| 327 | if is_BuiltIn_Call(callnode, 'Advance', 2): |
|---|
| 328 | #CARRYSET |
|---|
| 329 | rtn = self.carryvar.id + "." + "BitBlock_advance_n_<%i>" % callnode.args[1].n |
|---|
| 330 | c = mkCall(rtn, [callnode.args[0]] + adv_n_args) |
|---|
| 331 | self.current_adv_n += 1 |
|---|
| 332 | return c |
|---|
| 333 | if is_BuiltIn_Call(callnode, 'Advance', 1): |
|---|
| 334 | #CARRYSET |
|---|
| 335 | rtn = self.carryvar.id + "." + "BitBlock_advance_ci_co" |
|---|
| 336 | c = mkCall(rtn, callnode.args + carry_args) |
|---|
| 337 | self.current_carry += 1 |
|---|
| 338 | return c |
|---|
| 339 | elif is_BuiltIn_Call(callnode, 'Advance32', 1): |
|---|
| 340 | #CARRYSET |
|---|
| 341 | rtn = self.carryvar.id + "." + "BitBlock_advance_n_<32>" |
|---|
| 342 | c = mkCall(rtn, callnode.args + adv_n_args) |
|---|
| 343 | self.current_adv_n += 1 |
|---|
| 344 | return c |
|---|
| 345 | elif is_BuiltIn_Call(callnode, 'ScanThru', 2): |
|---|
| 346 | #CARRYSET |
|---|
| 347 | rtn = self.carryvar.id + "." + "BitBlock_scanthru_ci_co" |
|---|
| 348 | c = mkCall(rtn, callnode.args + carry_args) |
|---|
| 349 | self.current_carry += 1 |
|---|
| 350 | return c |
|---|
| 351 | elif is_BuiltIn_Call(callnode, 'AdvanceThenScanThru', 2): |
|---|
| 352 | #CARRYSET |
|---|
| 353 | rtn = self.carryvar.id + "." + "BitBlock_advance_then_scanthru" |
|---|
| 354 | c = mkCall(rtn, callnode.args + carry_args) |
|---|
| 355 | self.current_carry += 1 |
|---|
| 356 | return c |
|---|
| 357 | elif is_BuiltIn_Call(callnode, 'AdvanceThenScanTo', 2): |
|---|
| 358 | #CARRYSET |
|---|
| 359 | rtn = self.carryvar.id + "." + "BitBlock_advance_then_scanthru" |
|---|
| 360 | if self.carryout == "": scanclass = mkCall('simd_andc', [ast.Name('EOF_mask', ast.Load()), callnode.args[1]]) |
|---|
| 361 | else: scanclass = mkCall('simd_not', [callnode.args[1]]) |
|---|
| 362 | c = mkCall(rtn, [callnode.args[0], scanclass] + carry_args) |
|---|
| 363 | self.current_carry += 1 |
|---|
| 364 | return c |
|---|
| 365 | elif is_BuiltIn_Call(callnode, 'SpanUpTo', 2): |
|---|
| 366 | #CARRYSET |
|---|
| 367 | rtn = self.carryvar.id + "." + "BitBlock_span_upto" |
|---|
| 368 | c = mkCall(rtn, callnode.args + carry_args) |
|---|
| 369 | self.current_carry += 1 |
|---|
| 370 | return c |
|---|
| 371 | elif is_BuiltIn_Call(callnode, 'InclusiveSpan', 2): |
|---|
| 372 | #CARRYSET |
|---|
| 373 | # rtn = self.carryvar.id + "." + "BitBlock_span_upto" |
|---|
| 374 | # c = mkCall('simd_or', [mkCall(rtn, callnode.args + carry_args), callnode.args[1]]) |
|---|
| 375 | rtn = self.carryvar.id + "." + "BitBlock_inclusive_span" |
|---|
| 376 | c = mkCall(rtn, callnode.args + carry_args) |
|---|
| 377 | self.current_carry += 1 |
|---|
| 378 | return c |
|---|
| 379 | elif is_BuiltIn_Call(callnode, 'ExclusiveSpan', 2): |
|---|
| 380 | #CARRYSET |
|---|
| 381 | # rtn = self.carryvar.id + "." + "BitBlock_span_upto" |
|---|
| 382 | # c = mkCall('simd_andc', [mkCall(rtn, callnode.args + carry_args), callnode.args[0]]) |
|---|
| 383 | rtn = self.carryvar.id + "." + "BitBlock_exclusive_span" |
|---|
| 384 | c = mkCall(rtn, callnode.args + carry_args) |
|---|
| 385 | self.current_carry += 1 |
|---|
| 386 | return c |
|---|
| 387 | elif is_BuiltIn_Call(callnode, 'ScanTo', 2): |
|---|
| 388 | # Modified Oct. 9, 2011 to directly use BitBlock_scanthru, eliminating duplication |
|---|
| 389 | # in having a separate BitBlock_scanto routine. |
|---|
| 390 | #CARRYSET |
|---|
| 391 | rtn = self.carryvar.id + "." + "BitBlock_scanthru_ci_co" |
|---|
| 392 | if self.carryout == "": scanclass = mkCall('simd_andc', [ast.Name('EOF_mask', ast.Load()), callnode.args[1]]) |
|---|
| 393 | else: scanclass = mkCall('simd_not', [callnode.args[1]]) |
|---|
| 394 | c = mkCall(rtn, [callnode.args[0], scanclass] + carry_args) |
|---|
| 395 | self.current_carry += 1 |
|---|
| 396 | return c |
|---|
| 397 | elif is_BuiltIn_Call(callnode, 'ScanToFirst', 1): |
|---|
| 398 | #CARRYSET |
|---|
| 399 | rtn = self.carryvar.id + "." + "BitBlock_scantofirst" |
|---|
| 400 | #if self.carryout == "": carry_args = [ast.Name('EOF_mask', ast.Load())] + carry_args |
|---|
| 401 | c = mkCall(rtn, callnode.args + carry_args) |
|---|
| 402 | self.current_carry += 1 |
|---|
| 403 | return c |
|---|
| 404 | elif is_BuiltIn_Call(callnode, 'atEOF', 1): |
|---|
| 405 | if self.carryout != "": |
|---|
| 406 | # Non final block: atEOF(x) = 0. |
|---|
| 407 | return mkCall('simd<1>::constant<0>', []) |
|---|
| 408 | else: return mkCall('simd_andc', [callnode.args[0], ast.Name('EOF_mask', ast.Load())]) |
|---|
| 409 | elif is_BuiltIn_Call(callnode, 'inFile', 1): |
|---|
| 410 | if self.carryout != "": |
|---|
| 411 | # Non final block: inFile(x) = x. |
|---|
| 412 | return callnode.args[0] |
|---|
| 413 | else: return mkCall('simd_and', [callnode.args[0], ast.Name('EOF_mask', ast.Load())]) |
|---|
| 414 | elif is_BuiltIn_Call(callnode, 'StreamScan', 2): |
|---|
| 415 | rtn = "StreamScan" |
|---|
| 416 | c = mkCall(rtn, [ast.Name('(ScanBlock *) &' + callnode.args[0].id, ast.Load()), |
|---|
| 417 | ast.Name('sizeof(BitBlock)/sizeof(ScanBlock)', ast.Load()), |
|---|
| 418 | ast.Name(callnode.args[1].id, ast.Load())]) |
|---|
| 419 | return c |
|---|
| 420 | else: |
|---|
| 421 | #dump_Call(callnode) |
|---|
| 422 | return callnode |
|---|
| 423 | def visit_BinOp(self, exprnode): |
|---|
| 424 | self.generic_visit(exprnode) |
|---|
| 425 | carry_args = [ast.Num(self.current_carry)] |
|---|
| 426 | if self.carryin == "_ci": |
|---|
| 427 | carry_args = [mkCall(self.carryvar.id + "." + 'get_carry_in', [ast.Num(self.current_carry)]), ast.Num(self.current_carry)] |
|---|
| 428 | else: |
|---|
| 429 | carry_args = [mkCall('simd<1>::constant<0>', []), ast.Num(self.current_carry)] |
|---|
| 430 | if isinstance(exprnode.op, ast.Sub): |
|---|
| 431 | #CARRYSET |
|---|
| 432 | rtn = self.carryvar.id + "." + "BitBlock_sub_ci_co" |
|---|
| 433 | c = mkCall(rtn, [exprnode.left, exprnode.right] + carry_args) |
|---|
| 434 | self.current_carry += 1 |
|---|
| 435 | return c |
|---|
| 436 | elif isinstance(exprnode.op, ast.Add): |
|---|
| 437 | #CARRYSET |
|---|
| 438 | rtn = self.carryvar.id + "." + "BitBlock_add_ci_co" |
|---|
| 439 | c = mkCall(rtn, [exprnode.left, exprnode.right] + carry_args) |
|---|
| 440 | self.current_carry += 1 |
|---|
| 441 | return c |
|---|
| 442 | else: return exprnode |
|---|
| 443 | def visit_If(self, ifNode): |
|---|
| 444 | carry_base = self.current_carry |
|---|
| 445 | carries = CarryCounter().count(ifNode) |
|---|
| 446 | assert adv_nCounter().count(ifNode) == 0, "Advance(x,n) within if: illegal\n" |
|---|
| 447 | self.generic_visit(ifNode) |
|---|
| 448 | if carries == 0 or self.carryin == "": return ifNode |
|---|
| 449 | #CARRYSET |
|---|
| 450 | carry_arglist = [ast.Num(carry_base), ast.Num(carries)] |
|---|
| 451 | new_test = ast.BoolOp(ast.Or(), [ifNode.test, mkCall('carryQ.CarryTest', carry_arglist)]) |
|---|
| 452 | new_else_part = ifNode.orelse + [mkCallStmt('carryQ.CarryDequeueEnqueue', carry_arglist)] |
|---|
| 453 | return ast.If(new_test, ifNode.body, new_else_part) |
|---|
| 454 | def visit_While(self, whileNode): |
|---|
| 455 | if self.carryout == '': |
|---|
| 456 | whileNode.test.args[0] = mkCall("simd_and", [whileNode.test.args[0], ast.Name('EOF_mask', ast.Load())]) |
|---|
| 457 | carry_base = self.current_carry |
|---|
| 458 | assert adv_nCounter().count(whileNode) == 0, "Advance(x,n) within while: illegal\n" |
|---|
| 459 | carries = CarryCounter().count(whileNode) |
|---|
| 460 | #CARRYSET |
|---|
| 461 | if carries == 0: return whileNode |
|---|
| 462 | carry_arglist = [ast.Num(carry_base), ast.Num(carries)] |
|---|
| 463 | local_carryvar = 'subcarryQ' |
|---|
| 464 | inner_while = CarryIntro(local_carryvar, '', self.carryout).generic_xfrm(copy.deepcopy(whileNode)) |
|---|
| 465 | self.generic_visit(whileNode) |
|---|
| 466 | local_carry_decl = mkCallStmt('LocalCarryDeclare', [ast.Name(local_carryvar, ast.Load()), ast.Num(carries)]) |
|---|
| 467 | inner_while.body.insert(0, local_carry_decl) |
|---|
| 468 | final_combine = mkCallStmt('carryQ.CarryCombine', [ast.Attribute(ast.Name(local_carryvar, ast.Load()), 'cq', ast.Load()),ast.Num(carry_base), ast.Num(carries)]) |
|---|
| 469 | inner_while.body.append(final_combine) |
|---|
| 470 | #CARRYSET |
|---|
| 471 | if self.carryin == '': new_test = whileNode.test |
|---|
| 472 | else: new_test = ast.BoolOp(ast.Or(), [whileNode.test, mkCall('carryQ.CarryTest', carry_arglist)]) |
|---|
| 473 | else_part = [mkCallStmt('carryQ.CarryDequeueEnqueue', carry_arglist)] |
|---|
| 474 | return ast.If(new_test, whileNode.body + [inner_while], else_part) |
|---|
| 475 | |
|---|
| 476 | class StreamStructGen(ast.NodeVisitor): |
|---|
| 477 | """ |
|---|
| 478 | Given a BitStreamSet subclass, generate the equivalent C struct. |
|---|
| 479 | >>> obj = ast.parse(r''' |
|---|
| 480 | ... class S1(BitStreamSet): |
|---|
| 481 | ... a1 = 0 |
|---|
| 482 | ... a2 = 0 |
|---|
| 483 | ... a3 = 0 |
|---|
| 484 | ... |
|---|
| 485 | ... class S2(BitStreamSet): |
|---|
| 486 | ... x1 = 0 |
|---|
| 487 | ... x2 = 0 |
|---|
| 488 | ... ''') |
|---|
| 489 | >>> print StreamStructGen().gen(obj) |
|---|
| 490 | struct S1 { |
|---|
| 491 | BitBlock a1; |
|---|
| 492 | BitBlock a2; |
|---|
| 493 | BitBlock a3; |
|---|
| 494 | } self.current_adv_n = 0 |
|---|
| 495 | |
|---|
| 496 | |
|---|
| 497 | struct S2 { |
|---|
| 498 | BitBlock x1; |
|---|
| 499 | BitBlock x2; |
|---|
| 500 | } |
|---|
| 501 | """ |
|---|
| 502 | def __init__(self, asType=False): |
|---|
| 503 | self.asType = asType |
|---|
| 504 | def gen(self, tree): |
|---|
| 505 | self.Ccode="" |
|---|
| 506 | self.generic_visit(tree) |
|---|
| 507 | return self.Ccode |
|---|
| 508 | def gen_struct_types(self, tree): |
|---|
| 509 | self.asType = True |
|---|
| 510 | self.Ccode="" |
|---|
| 511 | self.generic_visit(tree) |
|---|
| 512 | return self.Ccode |
|---|
| 513 | def gen_struct_vars(self, tree): |
|---|
| 514 | self.asType = False |
|---|
| 515 | self.Ccode="" |
|---|
| 516 | self.generic_visit(tree) |
|---|
| 517 | return self.Ccode |
|---|
| 518 | def visit_ClassDef(self, node): |
|---|
| 519 | class_name = node.name[0].upper() + node.name[1:] |
|---|
| 520 | instance_name = node.name[0].lower() + node.name[1:] |
|---|
| 521 | self.Ccode += " struct " + class_name |
|---|
| 522 | if self.asType: |
|---|
| 523 | self.Ccode += " {\n" |
|---|
| 524 | for stmt in node.body: |
|---|
| 525 | if isinstance(stmt, ast.Assign): |
|---|
| 526 | for v in stmt.targets: |
|---|
| 527 | if isinstance(v, ast.Name): |
|---|
| 528 | self.Ccode += " BitBlock " + v.id + ";\n" |
|---|
| 529 | self.Ccode += "}" |
|---|
| 530 | else: self.Ccode += " " + instance_name |
|---|
| 531 | self.Ccode += ";\n\n" |
|---|
| 532 | |
|---|
| 533 | class StreamFunctionDecl(ast.NodeVisitor): |
|---|
| 534 | def __init__(self): |
|---|
| 535 | pass |
|---|
| 536 | def gen(self, tree): |
|---|
| 537 | self.Ccode="" |
|---|
| 538 | self.generic_visit(tree) |
|---|
| 539 | return self.Ccode |
|---|
| 540 | def visit_FunctionDef(self, node): |
|---|
| 541 | self.Ccode += "static inline void " + node.name + "(" |
|---|
| 542 | pending = "" |
|---|
| 543 | for arg in node.args.args: |
|---|
| 544 | if isinstance(arg, ast.Name): |
|---|
| 545 | self.Ccode += pending + arg.id.upper()[0] + arg.id[1:] + " & " + arg.id |
|---|
| 546 | pending = ", " |
|---|
| 547 | self.Ccode += ");\n" |
|---|
| 548 | |
|---|
| 549 | class AssertCompiler(ast.NodeTransformer): |
|---|
| 550 | def __init__(self): |
|---|
| 551 | self.assert_routine = ast.parse(error_routine).body[0].value |
|---|
| 552 | def xfrm(self, t): |
|---|
| 553 | return self.generic_visit(t) |
|---|
| 554 | def visit_Expr(self, node): |
|---|
| 555 | if isinstance(node.value, ast.Call): |
|---|
| 556 | if is_BuiltIn_Call(node.value, "assert_0", 2): |
|---|
| 557 | err_stream = node.value.args[0] |
|---|
| 558 | err_code = node.value.args[1] |
|---|
| 559 | return ast.If(err_stream, |
|---|
| 560 | [ast.Expr(mkCall(self.assert_routine, [err_code, err_stream]))], |
|---|
| 561 | []) |
|---|
| 562 | else: return node |
|---|
| 563 | else: return node |
|---|
| 564 | |
|---|
| 565 | # |
|---|
| 566 | # Adding Debugging Statements |
|---|
| 567 | # |
|---|
| 568 | class Add_SIMD_Register_Dump(ast.NodeTransformer): |
|---|
| 569 | def xfrm(self, t): |
|---|
| 570 | return self.generic_visit(t) |
|---|
| 571 | def visit_Assign(self, t): |
|---|
| 572 | self.generic_visit(t) |
|---|
| 573 | v = t.targets[0] |
|---|
| 574 | dump_stmt = mkCallStmt(' print_register<BitBlock>', [ast.Str(Cgen.py2C().gen(v)), v]) |
|---|
| 575 | return [t, dump_stmt] |
|---|
| 576 | |
|---|
| 577 | # |
|---|
| 578 | # Adding ASSERT_BITBLOCK_ALIGN macros |
|---|
| 579 | # |
|---|
| 580 | class Add_Assert_BitBlock_Align(ast.NodeTransformer): |
|---|
| 581 | def xfrm(self, t): |
|---|
| 582 | return self.generic_visit(t) |
|---|
| 583 | def visit_Assign(self, t): |
|---|
| 584 | self.generic_visit(t) |
|---|
| 585 | v = t.targets[0] |
|---|
| 586 | dump_stmt = mkCallStmt(' ASSERT_BITBLOCK_ALIGN', [v]) |
|---|
| 587 | return [t, dump_stmt] |
|---|
| 588 | |
|---|
| 589 | class StreamFunctionCarryCounter(ast.NodeVisitor): |
|---|
| 590 | def __init__(self): |
|---|
| 591 | self.carry_count = {} |
|---|
| 592 | |
|---|
| 593 | def count(self, node): |
|---|
| 594 | self.generic_visit(node) |
|---|
| 595 | return self.carry_count |
|---|
| 596 | |
|---|
| 597 | def visit_FunctionDef(self, node): |
|---|
| 598 | type_name = node.name[0].upper() + node.name[1:] |
|---|
| 599 | self.carry_count[type_name] = CarryCounter().count(node) |
|---|
| 600 | |
|---|
| 601 | class StreamFunctionCallXlator(ast.NodeTransformer): |
|---|
| 602 | def __init__(self, xlate_type="normal"): |
|---|
| 603 | self.stream_function_type_names = [] |
|---|
| 604 | self.xlate_type = xlate_type |
|---|
| 605 | |
|---|
| 606 | def xfrm(self, node, stream_function_type_names, C_syntax): |
|---|
| 607 | self.stream_function_type_names = stream_function_type_names |
|---|
| 608 | self.C_syntax = C_syntax |
|---|
| 609 | self.generic_visit(node) |
|---|
| 610 | |
|---|
| 611 | def visit_Call(self, node): |
|---|
| 612 | self.generic_visit(node) |
|---|
| 613 | |
|---|
| 614 | if isinstance(node, ast.Call) and isinstance(node.func, ast.Name):# and node.func.id in self.stream_function_type_names: |
|---|
| 615 | name = lower1(node.func.id) |
|---|
| 616 | node.func.id = name + ("_" if self.C_syntax else ".") + ("do_final_block" if self.xlate_type == "final" else "do_block") |
|---|
| 617 | if self.C_syntax: |
|---|
| 618 | node.args = [ast.Name(lower1(name), ast.Load())] + node.args |
|---|
| 619 | if self.xlate_type == "final": |
|---|
| 620 | node.args = node.args + [ast.Name("EOF_mask", ast.Load())] |
|---|
| 621 | |
|---|
| 622 | return node |
|---|
| 623 | |
|---|
| 624 | class StreamFunctionVisitor(ast.NodeVisitor): |
|---|
| 625 | def __init__(self,node): |
|---|
| 626 | self.stream_function_node = {} |
|---|
| 627 | self.generic_visit(node) |
|---|
| 628 | |
|---|
| 629 | def visit_FunctionDef(self, node): |
|---|
| 630 | key = node.name[0].upper() + node.name[1:] |
|---|
| 631 | self.stream_function_node[key] = node |
|---|
| 632 | |
|---|
| 633 | class StreamFunction(): |
|---|
| 634 | def __init__(self): |
|---|
| 635 | self.carry_count = 0 |
|---|
| 636 | self.adv_n_count = 0 |
|---|
| 637 | self.type_name = "" |
|---|
| 638 | self.instance_name = "" |
|---|
| 639 | self.parameters = "" |
|---|
| 640 | self.declarations = "" |
|---|
| 641 | self.initializations = "" |
|---|
| 642 | # |
|---|
| 643 | # TODO Consolidate *all* C code generation into the Emitter class. Medium priority. |
|---|
| 644 | # TODO Implement 'pretty print' indentation. Low priority. |
|---|
| 645 | # TODO Migrate Emiter() class to Emitter module. Medium priority. |
|---|
| 646 | |
|---|
| 647 | def lower1(name): |
|---|
| 648 | return name[0].lower() + name[1:] |
|---|
| 649 | def upper1(name): |
|---|
| 650 | return name[0].upper() + name[1:] |
|---|
| 651 | |
|---|
| 652 | def escape_newlines(str): |
|---|
| 653 | return str.replace('\n', '\\\n') |
|---|
| 654 | |
|---|
| 655 | class Emitter(): |
|---|
| 656 | def __init__(self, use_C_syntax): |
|---|
| 657 | self.use_C_syntax = use_C_syntax |
|---|
| 658 | |
|---|
| 659 | def definition(self, stream_function, icount=0): |
|---|
| 660 | |
|---|
| 661 | constructor = "" |
|---|
| 662 | carry_declaration = "" |
|---|
| 663 | self.type_name = stream_function.type_name |
|---|
| 664 | |
|---|
| 665 | if stream_function.carry_count > 0 or stream_function.adv_n_count > 0: |
|---|
| 666 | constructor = self.constructor(stream_function.type_name, stream_function.carry_count, stream_function.adv_n_count) |
|---|
| 667 | carry_declaration = self.carry_declare('carryQ', stream_function.carry_count, stream_function.adv_n_count) |
|---|
| 668 | |
|---|
| 669 | do_block_function = self.do_block(self.do_block_parameters(stream_function.parameters), |
|---|
| 670 | stream_function.declarations, |
|---|
| 671 | stream_function.initializations, |
|---|
| 672 | stream_function.statements) |
|---|
| 673 | |
|---|
| 674 | do_final_block_function = self.do_final_block(self.do_final_block_parameters(stream_function.parameters), |
|---|
| 675 | stream_function.declarations, |
|---|
| 676 | stream_function.initializations, |
|---|
| 677 | stream_function.final_block_statements) |
|---|
| 678 | |
|---|
| 679 | do_segment_function = self.do_segment(self.do_segment_parameters(stream_function.parameters), |
|---|
| 680 | self.do_segment_args(stream_function.parameters)) |
|---|
| 681 | |
|---|
| 682 | if self.use_C_syntax: |
|---|
| 683 | return self.indent(icount) + "struct " + stream_function.type_name + " {" \ |
|---|
| 684 | + "\n" + self.indent(icount) + carry_declaration \ |
|---|
| 685 | + "\n" + self.indent(icount) + "};\n" \ |
|---|
| 686 | + "\n" + self.indent(icount) + do_block_function \ |
|---|
| 687 | + "\n" + self.indent(icount) + do_final_block_function \ |
|---|
| 688 | + "\n" + self.indent(icount) + do_segment_function + "\n\n" |
|---|
| 689 | |
|---|
| 690 | return self.indent(icount) + "struct " + stream_function.type_name + " {" \ |
|---|
| 691 | + "\n" + self.indent(icount) + constructor \ |
|---|
| 692 | + "\n" + self.indent(icount) + do_block_function \ |
|---|
| 693 | + "\n" + self.indent(icount) + do_final_block_function \ |
|---|
| 694 | + "\n" + self.indent(icount) + do_segment_function \ |
|---|
| 695 | + "\n" + self.indent(icount) + carry_declaration \ |
|---|
| 696 | + "\n" + self.indent(icount) + "};\n\n" |
|---|
| 697 | |
|---|
| 698 | def constructor(self, type_name, carry_count, adv_n_count, icount=0): |
|---|
| 699 | adv_n_decl = "" |
|---|
| 700 | #for i in range(adv_n_count): adv_n_decl += self.indent(icount+2) + "pending64[%s] = simd<1>::constant<0>();\n" % i |
|---|
| 701 | return self.indent(icount) + "%s() { ""\n" % (type_name) + adv_n_decl + self.carry_init(carry_count) + " }" |
|---|
| 702 | |
|---|
| 703 | def do_block(self, parameters, declarations, initializations, statements, icount=0): |
|---|
| 704 | pfx = (lower1(self.type_name) + "_" if self.use_C_syntax else "") |
|---|
| 705 | if self.use_C_syntax: |
|---|
| 706 | return "#define " + pfx + "do_block(" + parameters + ")\\\n do {" \ |
|---|
| 707 | + "\\\n" + self.indent(icount) + escape_newlines(declarations) \ |
|---|
| 708 | + "\\\n" + self.indent(icount) + escape_newlines(initializations) \ |
|---|
| 709 | + "\\\n" + self.indent(icount) + escape_newlines(statements) \ |
|---|
| 710 | + "\\\n" + self.indent(icount + 2) + "} while (0)" |
|---|
| 711 | return self.indent(icount) + do_block_inline_decorator + "void " + pfx + "do_block(" + parameters + ") {" \ |
|---|
| 712 | + "\n" + self.indent(icount) + declarations \ |
|---|
| 713 | + "\n" + self.indent(icount) + initializations \ |
|---|
| 714 | + "\n" + self.indent(icount) + statements \ |
|---|
| 715 | + "\n" + self.indent(icount + 2) + "}" |
|---|
| 716 | |
|---|
| 717 | |
|---|
| 718 | |
|---|
| 719 | |
|---|
| 720 | def do_final_block(self, parameters, declarations, initializations, statements, icount=0): |
|---|
| 721 | pfx = (lower1(self.type_name) + "_" if self.use_C_syntax else "") |
|---|
| 722 | if self.use_C_syntax: |
|---|
| 723 | return "#define " + pfx + "do_final_block(" + parameters + ")\\\n do {" \ |
|---|
| 724 | + "\\\n" + self.indent(icount) + escape_newlines(declarations) \ |
|---|
| 725 | + "\\\n" + self.indent(icount) + escape_newlines(initializations) \ |
|---|
| 726 | + "\\\n" + self.indent(icount) + escape_newlines(statements) \ |
|---|
| 727 | + "\\\n" + self.indent(icount + 2) + "} while (0)" |
|---|
| 728 | return self.indent(icount) + do_final_block_inline_decorator + "void " + pfx + "do_final_block(" + parameters + ") {" \ |
|---|
| 729 | + "\n" + self.indent(icount) + declarations \ |
|---|
| 730 | + "\n" + self.indent(icount) + initializations \ |
|---|
| 731 | + "\n" + self.indent(icount) + statements \ |
|---|
| 732 | + "\n" + self.indent(icount + 2) + "}" |
|---|
| 733 | |
|---|
| 734 | def do_segment(self, parameters, do_block_call_args, icount=0): |
|---|
| 735 | pfx = (lower1(self.type_name) + "_" if self.use_C_syntax else "") |
|---|
| 736 | if self.use_C_syntax: |
|---|
| 737 | return "#define " + pfx + "do_segment(" + parameters + ")\\\n do {" \ |
|---|
| 738 | + "\\\n" + self.indent(icount) + " int i;" \ |
|---|
| 739 | + "\\\n" + self.indent(icount) + " for (i = 0; i < segment_blocks; i++)" \ |
|---|
| 740 | + "\\\n" + self.indent(icount) + " " + pfx + "do_block(" + do_block_call_args + ");" \ |
|---|
| 741 | + "\\\n" + self.indent(icount + 2) + "} while (0)" |
|---|
| 742 | return self.indent(icount) + "void " + pfx + "do_segment(" + parameters + ") {" \ |
|---|
| 743 | + "\n" + self.indent(icount) + " int i;" \ |
|---|
| 744 | + "\n" + self.indent(icount) + " for (i = 0; i < segment_blocks; i++)" \ |
|---|
| 745 | + "\n" + self.indent(icount) + " " + pfx + "do_block(" + do_block_call_args + ");" \ |
|---|
| 746 | + "\n" + self.indent(icount + 2) + "}" |
|---|
| 747 | |
|---|
| 748 | def declaration(self, type_name, instance_name, icount=0): |
|---|
| 749 | if self.use_C_syntax: return self.indent(icount) + "struct " + type_name + " " + instance_name + ";\n" |
|---|
| 750 | return self.indent(icount) + type_name + " " + instance_name + ";\n" |
|---|
| 751 | |
|---|
| 752 | def carry_init(self, carry_count, icount=0): |
|---|
| 753 | #CARRY SET |
|---|
| 754 | return "" |
|---|
| 755 | |
|---|
| 756 | def carry_declare(self, carry_variable, carry_count, adv_n_count=0, icount=0): |
|---|
| 757 | adv_n_decl = "" |
|---|
| 758 | #if adv_n_count > 0: |
|---|
| 759 | # adv_n_decl = "\n" + self.indent(icount) + "BitBlock pending64[%s];" % adv_n_count |
|---|
| 760 | #CARRY SET |
|---|
| 761 | return self.indent(icount) + "CarryArray<%i, %i> %s;" % (carry_count, adv_n_count, carry_variable) |
|---|
| 762 | |
|---|
| 763 | def carry_test(self, carry_variable, carry_count, icount=0): |
|---|
| 764 | #CARRY SET |
|---|
| 765 | return self.indent(icount) + "carryQ.CarryTest(0, %i)" % (carry_count) |
|---|
| 766 | |
|---|
| 767 | def indent(self, icount): |
|---|
| 768 | s = "" |
|---|
| 769 | for i in range(0,icount): s += " " |
|---|
| 770 | return s |
|---|
| 771 | |
|---|
| 772 | def do_block_parameters(self, parameters): |
|---|
| 773 | if self.use_C_syntax: |
|---|
| 774 | #return ", ".join([self.type_name + " * " + self.instance_name] + [upper1(p) + " * " + lower1(p) for p in parameters]) |
|---|
| 775 | return ", ".join([lower1(self.type_name)] + [lower1(p) for p in parameters]) |
|---|
| 776 | else: return ", ".join([upper1(p) + " & " + lower1(p) for p in parameters]) |
|---|
| 777 | |
|---|
| 778 | def do_final_block_parameters(self, parameters): |
|---|
| 779 | if self.use_C_syntax: |
|---|
| 780 | #return ", ".join([self.type_name + " * " + self.instance_name] + [upper1(p) + " * " + lower1(p) for p in parameters]+ ["BitBlock EOF_mask"]) |
|---|
| 781 | return ", ".join([lower1(self.type_name)] + [lower1(p) for p in parameters]+ ["EOF_mask"]) |
|---|
| 782 | else: return ", ".join([upper1(p) + " & " + lower1(p) for p in parameters]+ ["BitBlock EOF_mask"]) |
|---|
| 783 | |
|---|
| 784 | def do_segment_parameters(self, parameters): |
|---|
| 785 | if self.use_C_syntax: |
|---|
| 786 | #return ", ".join([self.type_name + " * " + + self.instance_name] + [upper1(p) + " " + lower1(p) + "[]" for p in parameters]) |
|---|
| 787 | return ", ".join([lower1(self.type_name)] + [lower1(p) for p in parameters] + ["int segment_blocks"]) |
|---|
| 788 | else: return ", ".join([upper1(p) + " " + lower1(p) + "[]" for p in parameters] + ["int segment_blocks"]) |
|---|
| 789 | |
|---|
| 790 | def do_segment_args(self, parameters): |
|---|
| 791 | if self.use_C_syntax: |
|---|
| 792 | return ", ".join([lower1(self.type_name)] + [lower1(p) + "[i]" for p in parameters]) |
|---|
| 793 | else: return ", ".join([lower1(p) + "[i]" for p in parameters]) |
|---|
| 794 | |
|---|
| 795 | def main(infilename, outfile = sys.stdout): |
|---|
| 796 | t = ast.parse(file(infilename).read()) |
|---|
| 797 | outfile.write(StreamStructGen(True).gen(t)) |
|---|
| 798 | outfile.write(FunctionXlator().xlat(t)) |
|---|
| 799 | |
|---|
| 800 | # |
|---|
| 801 | # Routines for compatibility with the old compiler/template. |
|---|
| 802 | # Quick and dirty hacks for now - Dec. 2010. |
|---|
| 803 | # |
|---|
| 804 | |
|---|
| 805 | class MainLoopTransformer: |
|---|
| 806 | def __init__(self, main_module, C_syntax=False, add_dump_stmts=False, add_assert_bitblock_align=False, main_node_id='Main'): |
|---|
| 807 | |
|---|
| 808 | self.main_module = main_module |
|---|
| 809 | self.main_node_id = main_node_id |
|---|
| 810 | self.use_C_syntax = C_syntax |
|---|
| 811 | self.add_dump_stmts = add_dump_stmts |
|---|
| 812 | self.add_assert_bitblock_align = add_assert_bitblock_align |
|---|
| 813 | |
|---|
| 814 | # Gather and partition function definition nodes. |
|---|
| 815 | stream_function_visitor = StreamFunctionVisitor(self.main_module) |
|---|
| 816 | self.stream_function_node = stream_function_visitor.stream_function_node |
|---|
| 817 | for key, node in self.stream_function_node.iteritems(): |
|---|
| 818 | AdvanceCombiner().xfrm(node) |
|---|
| 819 | self.main_node = self.stream_function_node[main_node_id] |
|---|
| 820 | self.main_carry_count = CarryCounter().count(self.main_node) |
|---|
| 821 | self.main_adv_n_count = adv_nCounter().count(self.main_node) |
|---|
| 822 | assert self.main_adv_n_count == 0, "Advance32() in main not supported.\n" |
|---|
| 823 | del self.stream_function_node[self.main_node_id] |
|---|
| 824 | |
|---|
| 825 | self.stream_functions = {} |
|---|
| 826 | for key, node in self.stream_function_node.iteritems(): |
|---|
| 827 | stream_function = StreamFunction() |
|---|
| 828 | stream_function.carry_count = CarryCounter().count(node) |
|---|
| 829 | stream_function.adv_n_count = adv_nCounter().count(node) |
|---|
| 830 | stream_function.type_name = node.name[0].upper() + node.name[1:] |
|---|
| 831 | stream_function.instance_name = node.name[0].lower() + node.name[1:] |
|---|
| 832 | stream_function.parameters = FunctionVars(node).params |
|---|
| 833 | stream_function.declarations = BitBlock_decls_of_fn(node) |
|---|
| 834 | stream_function.initializations = StreamInitializations().xfrm(node) |
|---|
| 835 | |
|---|
| 836 | StringMatchCompiler().xfrm(node) |
|---|
| 837 | AssertCompiler().xfrm(node) |
|---|
| 838 | AugAssignRemoval().xfrm(node) |
|---|
| 839 | Bitwise_to_SIMD().xfrm(node) |
|---|
| 840 | final_block_node = copy.deepcopy(node) |
|---|
| 841 | if self.use_C_syntax: |
|---|
| 842 | carryQname = stream_function.instance_name + ".carryQ" |
|---|
| 843 | else: carryQname = "carryQ" |
|---|
| 844 | CarryIntro(carryQname).xfrm_fndef(node) |
|---|
| 845 | CarryIntro(carryQname, "_ci", "").xfrm_fndef(final_block_node) |
|---|
| 846 | |
|---|
| 847 | if self.add_dump_stmts: |
|---|
| 848 | Add_SIMD_Register_Dump().xfrm(node) |
|---|
| 849 | Add_SIMD_Register_Dump().xfrm(final_block_node) |
|---|
| 850 | |
|---|
| 851 | if self.add_assert_bitblock_align: |
|---|
| 852 | Add_Assert_BitBlock_Align().xfrm(node) |
|---|
| 853 | Add_Assert_BitBlock_Align().xfrm(final_block_node) |
|---|
| 854 | |
|---|
| 855 | if stream_function.carry_count > 0: |
|---|
| 856 | node.body += [mkCallStmt('carryQ.CarryQ_Adjust', [ast.Num(stream_function.carry_count)])] |
|---|
| 857 | |
|---|
| 858 | stream_function.statements = Cgen.py2C(4).gen(node.body) |
|---|
| 859 | stream_function.final_block_statements = Cgen.py2C(4).gen(final_block_node.body) |
|---|
| 860 | self.stream_functions[stream_function.type_name] = stream_function |
|---|
| 861 | |
|---|
| 862 | self.emitter = Emitter(self.use_C_syntax) |
|---|
| 863 | |
|---|
| 864 | def any_carry_expr(self): |
|---|
| 865 | |
|---|
| 866 | carry_test = [] |
|---|
| 867 | |
|---|
| 868 | if self.main_carry_count > 0: |
|---|
| 869 | carry_test.append(self.emitter.carry_test('carryQ', self.main_carry_count)) |
|---|
| 870 | carry_test.append(" || ") |
|---|
| 871 | |
|---|
| 872 | for key in self.stream_functions.keys(): |
|---|
| 873 | if self.stream_functions[key].carry_count > 0: |
|---|
| 874 | carry_test.append(self.stream_functions[key].instance_name + "." + self.emitter.carry_test('carryQ',self.stream_functions[key].carry_count))# TODO Update self.emitter.carry_test |
|---|
| 875 | carry_test.append(" || ") |
|---|
| 876 | |
|---|
| 877 | if len(carry_test) > 0: |
|---|
| 878 | carry_test.pop() |
|---|
| 879 | return "".join(carry_test) |
|---|
| 880 | return "1" |
|---|
| 881 | |
|---|
| 882 | def gen_globals(self): |
|---|
| 883 | self.Cglobals = StreamStructGen().gen_struct_types(self.main_module) |
|---|
| 884 | for key in self.stream_functions.keys(): |
|---|
| 885 | self.Cglobals += Emitter(self.use_C_syntax).definition(self.stream_functions[key],2) |
|---|
| 886 | |
|---|
| 887 | def gen_declarations(self): |
|---|
| 888 | self.Cdecls = StreamStructGen().gen_struct_vars(self.main_module) |
|---|
| 889 | self.Cdecls += BitBlock_decls_of_fn(self.main_node) |
|---|
| 890 | if self.main_carry_count > 0: |
|---|
| 891 | self.Cdecls += self.emitter.carry_declare('carryQ', self.main_carry_count) |
|---|
| 892 | |
|---|
| 893 | def gen_initializations(self): |
|---|
| 894 | self.Cinits = "" |
|---|
| 895 | if self.main_carry_count > 0: |
|---|
| 896 | self.Cinits += self.emitter.carry_init(self.main_carry_count) |
|---|
| 897 | self.Cinits += StreamInitializations().xfrm(self.main_module) |
|---|
| 898 | if self.use_C_syntax: |
|---|
| 899 | for key in self.stream_functions.keys(): |
|---|
| 900 | if self.stream_functions[key].carry_count == 0: continue |
|---|
| 901 | self.Cinits += self.emitter.declaration(self.stream_functions[key].type_name, self.stream_functions[key].instance_name, 2) |
|---|
| 902 | self.Cinits += "CarryInit(" + self.stream_functions[key].instance_name + ".carryQ, %i);\n" % (self.stream_functions[key].carry_count) |
|---|
| 903 | else: |
|---|
| 904 | for key in self.stream_functions.keys(): |
|---|
| 905 | self.Cinits += self.emitter.declaration(self.stream_functions[key].type_name, self.stream_functions[key].instance_name, 2) |
|---|
| 906 | |
|---|
| 907 | |
|---|
| 908 | def xfrm_block_stmts(self): |
|---|
| 909 | StringMatchCompiler().xfrm(self.main_node) |
|---|
| 910 | AugAssignRemoval().xfrm(self.main_node) |
|---|
| 911 | Bitwise_to_SIMD().xfrm(self.main_node) |
|---|
| 912 | Bitwise_to_SIMD().xfrm(self.main_node) |
|---|
| 913 | AssertCompiler().xfrm(self.main_node) |
|---|
| 914 | final_block_main = copy.deepcopy(self.main_node) |
|---|
| 915 | CarryIntro().xfrm_fndef(self.main_node) |
|---|
| 916 | CarryIntro('carryQ', '_ci', '').xfrm_fndef(final_block_main) |
|---|
| 917 | if self.add_dump_stmts: |
|---|
| 918 | Add_SIMD_Register_Dump().xfrm(self.main_node) |
|---|
| 919 | Add_SIMD_Register_Dump().xfrm(final_block_main) |
|---|
| 920 | |
|---|
| 921 | if self.add_assert_bitblock_align: |
|---|
| 922 | print "add_assert_bitblock_align" |
|---|
| 923 | Add_Assert_BitBlock_Align().xfrm(self.main_node) |
|---|
| 924 | Add_Assert_BitBlock_Align().xfrm(final_block_main) |
|---|
| 925 | |
|---|
| 926 | StreamFunctionCallXlator().xfrm(self.main_node, self.stream_function_node.keys(), self.use_C_syntax) |
|---|
| 927 | StreamFunctionCallXlator('final').xfrm(final_block_main, self.stream_function_node.keys(), self.use_C_syntax) |
|---|
| 928 | |
|---|
| 929 | if self.main_carry_count > 0: |
|---|
| 930 | #self.main_node.body += [mkCallStmt('CarryQ_Adjust', [ast.Name('carryQ', ast.Load()), ast.Num(self.main_carry_count)])] |
|---|
| 931 | self.main_node.body += [mkCallStmt('carryQ.CarryQ_Adjust', [ast.Num(self.main_carry_count)])] |
|---|
| 932 | |
|---|
| 933 | |
|---|
| 934 | |
|---|
| 935 | self.Cstmts = Cgen.py2C().gen(self.main_node.body) |
|---|
| 936 | self.Cfinal_stmts = Cgen.py2C().gen(final_block_main.body) |
|---|
| 937 | |
|---|
| 938 | if __name__ == "__main__": |
|---|
| 939 | import doctest |
|---|
| 940 | doctest.testmod() |
|---|