示例#1
0
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)
示例#2
0
    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
示例#3
0
文件: code_parser.py 项目: phrb/Orio
def p_primary_expression_3(p):
    "primary_expression : FCONST"
    val = float(p[1])
    p[0] = ast.NumLitExp(val, ast.NumLitExp.FLOAT)
示例#4
0
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)
示例#5
0
    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)
示例#6
0
文件: code_parser.py 项目: phrb/Orio
def p_primary_expression_2(p):
    "primary_expression : ICONST"
    val = int(p[1])
    p[0] = ast.NumLitExp(val, ast.NumLitExp.INT)
示例#7
0
    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__)
示例#8
0
    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__)
示例#9
0
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)))
示例#10
0
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)))
示例#11
0
文件: ast_util.py 项目: zhjp0/Orio
    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)