def p_primary_expression_3(p): 'primary_expression : FCONST' val = float(p[1]) p[0] = ast.NumLitExp(val, ast.NumLitExp.FLOAT, p.lineno(1) + __start_line_no - 1)
def getForLoopInfo(self, stmt): ''' Given a for-loop statement, extract information about its loop structure. Note that the for-loop must be in the following form: for (<id> = <exp>; <id> <= <exp>; <id> += <exp>) <stmt> Subtraction is not considered at the iteration expression for the sake of the implementation simplicity. ''' # get rid of compound statement that contains only a single statement while isinstance(stmt, ast.CompStmt) and len(stmt.stmts) == 1: stmt = stmt.stmts[0] # check if it is a for-loop statement if not isinstance(stmt, ast.ForStmt): err('orio.module.ortil.ast_util: OrTil:%s: not a for-loop statement' % stmt.line_no) # check initialization expression if stmt.init: while True: while isinstance(stmt.init, ast.ParenthExp): stmt.init = stmt.init.exp if (isinstance(stmt.init, ast.BinOpExp) and stmt.init.op_type == ast.BinOpExp.EQ_ASGN): while isinstance(stmt.init.lhs, ast.ParenthExp): stmt.init.lhs = stmt.init.lhs.exp while isinstance(stmt.init.rhs, ast.ParenthExp): stmt.init.rhs = stmt.init.rhs.exp if isinstance(stmt.init.lhs, ast.IdentExp): break err('orio.module.ortil.ast_util:%s: loop initialization expression not in "<id> = <exp>" form' % stmt.init.line_no) # check test expression if stmt.test: while True: while isinstance(stmt.test, ast.ParenthExp): stmt.test = stmt.test.exp if (isinstance(stmt.test, ast.BinOpExp) and stmt.test.op_type in (ast.BinOpExp.LT, ast.BinOpExp.LE)): while isinstance(stmt.test.lhs, ast.ParenthExp): stmt.test.lhs = stmt.test.lhs.exp while isinstance(stmt.test.rhs, ast.ParenthExp): stmt.test.rhs = stmt.test.rhs.exp if isinstance(stmt.test.lhs, ast.IdentExp): break err('orio.module.ortil.ast_util:%s: loop test expression not in "<id> <= <exp>" or ' + '"<id> < <exp>"form' % stmt.test.line_no) # check iteration expression if stmt.iter: while True: while isinstance(stmt.iter, ast.ParenthExp): stmt.iter = stmt.iter.exp if (isinstance(stmt.iter, ast.BinOpExp) and stmt.iter.op_type == ast.BinOpExp.EQ_ASGN): while isinstance(stmt.iter.lhs, ast.ParenthExp): stmt.iter.lhs = stmt.iter.lhs.exp while isinstance(stmt.iter.rhs, ast.ParenthExp): stmt.iter.rhs = stmt.iter.rhs.exp if isinstance(stmt.iter.lhs, ast.IdentExp): if (isinstance(stmt.iter.rhs, ast.BinOpExp) and stmt.iter.rhs.op_type in (ast.BinOpExp.ADD, ast.BinOpExp.SUB)): while isinstance(stmt.iter.rhs.lhs, ast.ParenthExp): stmt.iter.rhs.lhs = stmt.iter.rhs.lhs.exp while isinstance(stmt.iter.rhs.rhs, ast.ParenthExp): stmt.iter.rhs.rhs = stmt.iter.rhs.rhs.exp if (isinstance(stmt.iter.rhs.lhs, ast.IdentExp) and stmt.iter.lhs.name == stmt.iter.rhs.lhs.name): break elif (isinstance(stmt.iter, ast.UnaryExp) and stmt.iter.op_type in (ast.UnaryExp.POST_INC, ast.UnaryExp.PRE_INC, ast.UnaryExp.POST_DEC, ast.UnaryExp.PRE_DEC)): while isinstance(stmt.iter.exp, ast.ParenthExp): stmt.iter.exp = stmt.iter.exp.exp if isinstance(stmt.iter.exp, ast.IdentExp): break err(( 'orio.module.ortil.ast_util:%s: loop iteration expression not in "<id>++" or "<id>--" or ' + '"<id> += <exp>" or "<id> = <id> + <exp>" form') % stmt.iter.line_no) # check if the control expressions are all empty if not stmt.init and not stmt.test and not stmt.iter: err('orio.module.ortil.ast_util:%s: a loop with an empty control expression cannot be handled' % stmt.line_no) # check if the iterator names are all the same init_iname = None test_iname = None iter_iname = None if stmt.init: init_iname = stmt.init.lhs.name if stmt.test: test_iname = stmt.test.lhs.name if stmt.iter: if isinstance(stmt.iter, ast.BinOpExp): iter_iname = stmt.iter.lhs.name else: assert (isinstance( stmt.iter, ast.UnaryExp)), 'internal error:OrTil: not unary' iter_iname = stmt.iter.exp.name inames = [] if init_iname: inames.append(init_iname) if test_iname: inames.append(test_iname) if iter_iname: inames.append(iter_iname) if inames.count(inames[0]) != len(inames): err('orio.module.ortil.ast_util:%s: iterator names across init, test, and iter exps must be the same' % stmt.line_no) # extract for-loop structure information index_id = ast.IdentExp(inames[0]) lbound_exp = None ubound_exp = None stride_exp = None if stmt.init: lbound_exp = stmt.init.rhs.replicate() if stmt.test: if stmt.test.op_type == ast.BinOpExp.LT: ubound_exp = ast.BinOpExp(stmt.test.rhs.replicate(), ast.NumLitExp(1, ast.NumLitExp.INT), ast.BinOpExp.SUB) else: ubound_exp = stmt.test.rhs.replicate() if stmt.iter: if isinstance(stmt.iter, ast.BinOpExp): stride_exp = stmt.iter.rhs.rhs.replicate() if isinstance(stride_exp, ast.BinOpExp): stride_exp = ast.ParenthExp(stride_exp) if stmt.iter.rhs.op_type == ast.BinOpExp.SUB: stride_exp = ast.UnaryExp(stride_exp, ast.UnaryExp.MINUS) elif isinstance(stmt.iter, ast.UnaryExp): if stmt.iter.op_type in (ast.UnaryExp.POST_INC, ast.UnaryExp.PRE_INC): stride_exp = ast.NumLitExp(1, ast.NumLitExp.INT) elif stmt.iter.op_type in (ast.UnaryExp.POST_DEC, ast.UnaryExp.PRE_DEC): stride_exp = ast.NumLitExp(-1, ast.NumLitExp.INT) else: err('orio.module.ortil.ast_util internal error:OrTil: unexpected unary operation type' ) else: err('orio.module.ortil.ast_utilinternal error:OrTil: unexpected type of iteration expression' ) loop_body = stmt.stmt.replicate() for_loop_info = (index_id, lbound_exp, ubound_exp, stride_exp, loop_body) # return the for-loop structure information return for_loop_info
def p_primary_expression_3(p): "primary_expression : FCONST" val = float(p[1]) p[0] = ast.NumLitExp(val, ast.NumLitExp.FLOAT)
def p_primary_expression_2(p): 'primary_expression : ICONST' val = int(p[1]) p[0] = ast.NumLitExp(val, ast.NumLitExp.INT, p.lineno(1) + __start_line_no - 1)
def __getLoopBoundScanningStmts(self, stmts, tile_level, outer_loop_inames, loop_info_table): ''' Generate an explicit loop-bound scanning code used at runtime to determine the latest start and the earliest end of scanning full tiles. ''' # (optimization) generate code that determines the loop bounds of full tiles at compile time if self.affine_lbound_exps: return self.__staticLoopBoundScanning(stmts, tile_level, outer_loop_inames, loop_info_table) # initialize all returned variables scan_stmts = [] lbound_info_seq = [] int_vars = [] # iterate over each statement to find loop bounds that are functions of outer loop iterators min_int = ast.NumLitExp(-2147483648, ast.NumLitExp.INT) max_int = ast.NumLitExp(2147483647, ast.NumLitExp.INT) lb_exps_table = {} ub_exps_table = {} pre_scan_stmts = [] post_scan_stmts = [] scan_loops = SimpleLoops() for stmt in stmts: # skip all non loop statements if not isinstance(stmt, ast.ForStmt): lbound_info_seq.append(None) continue # extract this loop structure id, lb_exp, ub_exp, st_exp, lbody = self.ast_util.getForLoopInfo( stmt) # see if the loop bound expressions are bound/free of outer loop iterators lb_inames = filter( lambda i: self.ast_util.containIdentName(lb_exp, i), outer_loop_inames) ub_inames = filter( lambda i: self.ast_util.containIdentName(ub_exp, i), outer_loop_inames) # skip loops with bound expressions that are free of outer loop iterators if not lb_inames and not ub_inames: lbound_info_seq.append(None) continue # check if this loop runs only once is_one_time_loop = str(lb_exp) == str(ub_exp) # generate booleans to indicate the needs of prolog, epilog, and orio.main.tiled loop if is_one_time_loop: need_tiled_loop = False need_prolog = False need_epilog = False else: need_tiled_loop = True need_prolog = len(lb_inames) > 0 need_epilog = len(ub_inames) > 0 # generate new variable names for both the new lower and upper loop bounds if need_tiled_loop: lb_name, ub_name = self.__getLoopBoundNames() int_vars.extend([lb_name, ub_name]) else: lb_name = '' ub_name = '' # append information about the new loop bounds lbinfo = (lb_name, ub_name, need_prolog, need_epilog, need_tiled_loop) lbound_info_seq.append(lbinfo) # skip generating loop-bound scanning code (if it's a one-time loop) if not need_tiled_loop: continue # generate loop-bound scanning code for the prolog if str(lb_exp) in lb_exps_table: lb_var = lb_exps_table[str(lb_exp)] a = ast.BinOpExp(ast.IdentExp(lb_name), lb_var.replicate(), ast.BinOpExp.EQ_ASGN) post_scan_stmts.append(ast.ExpStmt(a)) else: if need_prolog: a = ast.BinOpExp(ast.IdentExp(lb_name), min_int.replicate(), ast.BinOpExp.EQ_ASGN) pre_scan_stmts.append(ast.ExpStmt(a)) a = ast.BinOpExp( ast.IdentExp(lb_name), ast.FunCallExp( ast.IdentExp('max'), [ast.IdentExp(lb_name), lb_exp.replicate()]), ast.BinOpExp.EQ_ASGN) scan_loops.insertLoop(lb_inames, ast.ExpStmt(a)) else: a = ast.BinOpExp(ast.IdentExp(lb_name), lb_exp.replicate(), ast.BinOpExp.EQ_ASGN) pre_scan_stmts.append(ast.ExpStmt(a)) lb_exps_table[str(lb_exp)] = ast.IdentExp(lb_name) # generate loop-bound scaning code for the epilog if str(ub_exp) in ub_exps_table: ub_var = ub_exps_table[str(ub_exp)] a = ast.BinOpExp(ast.IdentExp(ub_name), ub_var.replicate(), ast.BinOpExp.EQ_ASGN) post_scan_stmts.append(ast.ExpStmt(a)) else: if need_epilog: a = ast.BinOpExp(ast.IdentExp(ub_name), max_int.replicate(), ast.BinOpExp.EQ_ASGN) pre_scan_stmts.append(ast.ExpStmt(a)) a = ast.BinOpExp( ast.IdentExp(ub_name), ast.FunCallExp( ast.IdentExp('min'), [ast.IdentExp(ub_name), ub_exp.replicate()]), ast.BinOpExp.EQ_ASGN) scan_loops.insertLoop(ub_inames, ast.ExpStmt(a)) else: a = ast.BinOpExp(ast.IdentExp(ub_name), ub_exp.replicate(), ast.BinOpExp.EQ_ASGN) pre_scan_stmts.append(ast.ExpStmt(a)) ub_exps_table[str(ub_exp)] = ast.IdentExp(ub_name) # build a new loop information tabe for generating the loop-bound scanning code n_loop_info_table = {} for iname, linfo in loop_info_table.items(): _, _, _, st_exp, _ = linfo n_loop_info_table[iname] = (self.__getTileSizeName( iname, tile_level), self.__getTileIterName(iname, tile_level), st_exp) # convert the "SimpleLoop" abstractions into loop ASTs scan_loop_stmts = scan_loops.convertToASTs(tile_level, n_loop_info_table) # merge all scanning statements scan_stmts = pre_scan_stmts + scan_loop_stmts + post_scan_stmts # return all necessary information return (scan_stmts, lbound_info_seq, int_vars)
def p_primary_expression_2(p): "primary_expression : ICONST" val = int(p[1]) p[0] = ast.NumLitExp(val, ast.NumLitExp.INT)
def __addIdentWithConstant(self, tnode, iname, constant): """Add with the given constant all identifiers that match to the specified name""" if isinstance(tnode, ast.NumLitExp): return tnode elif isinstance(tnode, ast.StringLitExp): return tnode elif isinstance(tnode, ast.IdentExp): if tnode.name == iname: a = ast.BinOpExp( tnode.replicate(), ast.NumLitExp(constant, ast.NumLitExp.INT), ast.BinOpExp.ADD, ) return ast.ParenthExp(a) else: return tnode elif isinstance(tnode, ast.ArrayRefExp): tnode.exp = self.__addIdentWithConstant(tnode.exp, iname, constant) tnode.sub_exp = self.__addIdentWithConstant( tnode.sub_exp, iname, constant) if self.constant_folding: tnode.exp = self.__foldConstant(tnode.exp) tnode.sub_exp = self.__foldConstant(tnode.sub_exp) return tnode elif isinstance(tnode, ast.FunCallExp): tnode.exp = self.__addIdentWithConstant(tnode.exp, iname, constant) tnode.args = [ self.__addIdentWithConstant(a, iname, constant) for a in tnode.args ] return tnode elif isinstance(tnode, ast.UnaryExp): tnode.exp = self.__addIdentWithConstant(tnode.exp, iname, constant) return tnode elif isinstance(tnode, ast.BinOpExp): tnode.lhs = self.__addIdentWithConstant(tnode.lhs, iname, constant) tnode.rhs = self.__addIdentWithConstant(tnode.rhs, iname, constant) return tnode elif isinstance(tnode, ast.ParenthExp): tnode.exp = self.__addIdentWithConstant(tnode.exp, iname, constant) return tnode elif isinstance(tnode, ast.ExpStmt): if tnode.exp: tnode.exp = self.__addIdentWithConstant( tnode.exp, iname, constant) return tnode elif isinstance(tnode, ast.CompStmt): tnode.stmts = [ self.__addIdentWithConstant(s, iname, constant) for s in tnode.stmts ] return tnode elif isinstance(tnode, ast.IfStmt): tnode.test = self.__addIdentWithConstant(tnode.test, iname, constant) tnode.true_stmt = self.__addIdentWithConstant( tnode.true_stmt, iname, constant) if tnode.false_stmt: tnode.false_stmt = self.__addIdentWithConstant( tnode.false_stmt, iname, constant) return tnode elif isinstance(tnode, ast.ForStmt): if tnode.init: tnode.init = self.__addIdentWithConstant( tnode.init, iname, constant) if tnode.test: tnode.test = self.__addIdentWithConstant( tnode.test, iname, constant) if tnode.iter: tnode.iter = self.__addIdentWithConstant( tnode.iter, iname, constant) tnode.stmt = self.__addIdentWithConstant(tnode.stmt, iname, constant) return tnode else: err("orio.module.ortildriver.transformation internal error: unknown type of AST: %s" % tnode.__class__.__name__)
def __foldConstantExp(self, exp, up_sign): """ To perform a simple (not full-fledged) constant folding optimization on the given expression A list is used to represent a k-ary addition. A tuple is used to represent a k-ary multiplication. """ if isinstance(exp, ast.NumLitExp): if up_sign == -1: exp.val *= -1 return exp elif isinstance(exp, ast.StringLitExp): if up_sign == -1: return ast.UnaryExp(exp, ast.UnaryExp.MINUS) return exp elif isinstance(exp, ast.IdentExp): if up_sign == -1: return ast.UnaryExp(exp, ast.UnaryExp.MINUS) return exp elif isinstance(exp, ast.ArrayRefExp): exp.exp = self.__foldConstantExp(exp.exp, 1) exp.sub_exp = self.__foldConstantExp(exp.sub_exp, 1) if up_sign == -1: return ast.UnaryExp(exp, ast.UnaryExp.MINUS) return exp elif isinstance(exp, ast.FunCallExp): exp.exp = self.__foldConstantExp(exp.exp, 1) exp.args = [self.__foldConstantExp(a, 1) for a in exp.args] if up_sign == -1: return ast.UnaryExp(exp, ast.UnaryExp.MINUS) return exp elif isinstance(exp, ast.UnaryExp): if exp.op_type == ast.UnaryExp.MINUS: up_sign *= -1 return self.__foldConstantExp(exp.exp, up_sign) elif isinstance(exp, ast.BinOpExp): if exp.op_type in (ast.BinOpExp.ADD, ast.BinOpExp.SUB): if exp.op_type == ast.BinOpExp.ADD: if up_sign == -1: lhs_sign = -1 rhs_sign = -1 else: lhs_sign = 1 rhs_sign = 1 else: if up_sign == -1: lhs_sign = -1 rhs_sign = 1 else: lhs_sign = 1 rhs_sign = -1 lhs = self.__foldConstantExp(exp.lhs, lhs_sign) rhs = self.__foldConstantExp(exp.rhs, rhs_sign) ops = [] for e in [lhs, rhs]: if isinstance(e, list): ops.extend(e) else: ops.append(e) add_num = 0 n_ops = [] for o in ops: if isinstance(o, ast.NumLitExp): add_num += o.val else: n_ops.append(o) ops = n_ops if add_num != 0: ops.append(ast.NumLitExp(add_num, ast.NumLitExp.INT)) if len(ops) == 0: return ast.NumLitExp(0, ast.NumLitExp.INT) elif len(ops) == 1: return ops[0] else: return ops elif exp.op_type == ast.BinOpExp.MUL: lhs = self.__foldConstantExp(exp.lhs, up_sign) rhs = self.__foldConstantExp(exp.rhs, 1) ops1 = [] ops2 = [] if isinstance(lhs, list): ops1.extend(lhs) else: ops1.append(lhs) if isinstance(rhs, list): ops2.extend(rhs) else: ops2.append(rhs) ops = [] for o1 in ops1: if isinstance(o1, tuple): o1 = list(o1) else: o1 = [o1] for o2 in ops2: if isinstance(o2, tuple): o2 = list(o2) else: o2 = [o2] o1 = [o.replicate() for o in o1] o2 = [o.replicate() for o in o2] o = [] mul_num = 1 for i in o1 + o2: if isinstance(i, ast.NumLitExp): mul_num *= i.val else: o.append(i) if mul_num != 0: if mul_num != 1: o.insert( 0, ast.NumLitExp(mul_num, ast.NumLitExp.INT)) if len(o) == 0: ops.append(ast.NumLitExp(1, ast.NumLitExp.INT)) elif len(o) == 1: ops.append(o[0]) else: ops.append(tuple(o)) add_num = 0 n_ops = [] for o in ops: if isinstance(o, ast.NumLitExp): add_num += o.val else: n_ops.append(o) ops = n_ops if add_num != 0: ops.append(ast.NumLitExp(add_num, ast.NumLitExp.INT)) if len(ops) == 0: return ast.NumLitExp(0, ast.NumLitExp.INT) elif len(ops) == 1: return ops[0] else: return ops else: err("orio.module.ortildriver.transformation: constant folding cannot handle binary operations other " + "than +,-,*") elif isinstance(exp, ast.ParenthExp): return self.__foldConstantExp(exp.exp, up_sign) else: err("orio.module.ortildriver.transformation internal error: unknown type of expression: %s" % exp.__class__.__name__)
def p_primary_expression_3(p): "primary_expression : FCONST" val = float(p[1]) p[0] = ast.NumLitExp(val, ast.NumLitExp.FLOAT, getLineNumber(p.lineno(1)))
def p_primary_expression_2(p): "primary_expression : ICONST" val = int(p[1]) p[0] = ast.NumLitExp(val, ast.NumLitExp.INT, getLineNumber(p.lineno(1)))
def getForLoopInfo(self, stmt): ''' Return information about the loop structure. for (id = lb; id <= ub; id = id + st) bod ''' # get rid of compound statement that contains only a single statement while isinstance(stmt, ast.CompStmt) and len(stmt.stmts) == 1: stmt = stmt.stmts[0] # check if it is a loop if not isinstance(stmt, ast.ForStmt): err('orio.module.tilic.ast_util: Tilic: input not a loop statement' ) # check loop initialization if stmt.init: if not (isinstance(stmt.init, ast.BinOpExp) and stmt.init.op_type == ast.BinOpExp.EQ_ASGN and isinstance(stmt.init.lhs, ast.IdentExp)): err('orio.module.tilic.ast_util: Tilic: loop initialization not in "id = lb" form' ) # check loop test if stmt.test: if not (isinstance(stmt.test, ast.BinOpExp) and stmt.test.op_type in (ast.BinOpExp.LE, ast.BinOpExp.LT) and isinstance(stmt.test.lhs, ast.IdentExp)): err('orio.module.tilic.ast_util: Tilic: loop test not in "id <= ub" or "id < ub" form' ) # check loop iteration if stmt.iter: if not ((isinstance(stmt.iter, ast.BinOpExp) and stmt.iter.op_type == ast.BinOpExp.EQ_ASGN and isinstance(stmt.iter.lhs, ast.IdentExp) and isinstance(stmt.iter.rhs, ast.BinOpExp) and isinstance(stmt.iter.rhs.lhs, ast.IdentExp) and stmt.iter.rhs.op_type == ast.BinOpExp.ADD and stmt.iter.lhs.name == stmt.iter.rhs.lhs.name) or (isinstance(stmt.iter, ast.UnaryExp) and isinstance( stmt.iter.exp, ast.IdentExp) and stmt.iter.op_type in (ast.UnaryExp.PRE_INC, ast.UnaryExp.POST_INC))): err('orio.module.tilic.ast_util: Tilic: loop iteration not in "id++" or "id += st" or "id = id + st" form' ) # check if the control expressions are all empty if not stmt.init and not stmt.test and not stmt.iter: err('orio.module.tilic.ast_util: Tilic: loop with an empty control expression cannot be handled' ) # check if the iterator names in the control expressions are all the same inames = [] if stmt.init: inames.append(stmt.init.lhs.name) if stmt.test: inames.append(stmt.test.lhs.name) if stmt.iter: if isinstance(stmt.iter, ast.BinOpExp): inames.append(stmt.iter.lhs.name) else: inames.append(stmt.iter.exp.name) if inames.count(inames[0]) != len(inames): err('orio.module.tilic.ast_util: Tilic: different iterator names used in the loop control expressions' ) # extract the loop structure information id = ast.IdentExp(inames[0]) lb = None ub = None st = None if stmt.init: lb = stmt.init.rhs.replicate() if stmt.test: if stmt.test.op_type == ast.BinOpExp.LT: ub = ast.BinOpExp(stmt.test.rhs.replicate(), ast.NumLitExp(1, ast.NumLitExp.INT), ast.BinOpExp.SUB) else: ub = stmt.test.rhs.replicate() if stmt.iter: if isinstance(stmt.iter, ast.BinOpExp): st = stmt.iter.rhs.rhs.replicate() else: st = ast.NumLitExp(1, ast.NumLitExp.INT) bod = stmt.stmt.replicate() # return the loop structure information return (id, lb, ub, st, bod)