parameters: (parent_vars_dict, if_vars_dict, else_vars_dict,
                        after_ifelse_vars_dict)
return_statement: return return_ids, modified_vars_from_parent, new_vars_to_create
docstring: Find out the ast.Name list of output by analyzing node's AST information.
      One of the following conditions should be satisfied while determining whether a variable is a return value:
      1. the var in parent scope is modified in If.body or If.orelse node.
      2. new var is both created in If.body and If.orelse node.
      3. new var is created only in one of If.body or If.orelse node, and it used as gast.Load firstly after gast.If node.
  
      For example:
          x, y = 5, 10
          if x > 4:
              x = x+1
              z = x*x
              q = 10
          else:
              y = y - 1
              z = y*y
              m = 20
              n = 20
  
          print(q)
          n = 30
          print(n)
  
  
      The return_ids are (x, y, z, q) for `If.body` and `If.orelse`node, because
      1. x is modified in If.body node,
      2. y is modified in If.body node,
      3. z is both created in If.body and If.orelse node,
      4. q is created only in If.body, and it is used by `print(q)` as gast.Load.
      Note:
          After transformed, q and z are created in parent scope. For example,
  
          x, y = 5, 10
          q = paddle.jit.dy2static.data_layer_not_check(name='q', shape=[-1], dtype='float32')
          z = paddle.jit.dy2static.data_layer_not_check(name='z', shape=[-1], dtype='float32')
  
          def true_func(x, y, q):
              x = x+1
              z = x*x
              q = 10
              return x,y,z,q
  
          def false_func(x, y, q):
              y = y - 1
              z = y*y
              m = 20
              n = 20
              return x,y,z,q
  
          x,y,z,q = fluid.layers.cond(x>4, lambda: true_func(x, y), lambda: false_func(x, y, q))
  
      m and n are not in return_ids, because
      5. m is created only in If.orelse, but it is not used after gast.If node.
      6. n is created only in If.orelse, and it is used by `n = 30` and `print(n)`, but it is not used as gast.Load firstly but gast.Store .
docstring_summary: Find out the ast.Name list of output by analyzing node's AST information.
      One of the following conditions should be satisfied while determining whether a variable is a return value:
      1. the var in parent scope is modified in If.body or If.orelse node.
      2. new var is both created in If.body and If.orelse node.
      3. new var is created only in one of If.body or If.orelse node, and it used as gast.Load firstly after gast.If node.
docstring_tokens: Find out the ast . Name list of output by analyzing node s AST information . One of the following conditions should be satisfied while determining whether a variable is a return value : 1 . the var in parent scope is modified in If . body or If . orelse node . 2 . new var is both created in If . body and If . orelse node . 3 . new var is created only in one of If . body or If . orelse node and it used as gast . Load firstly after gast . If node .
function: def parse_cond_return(parent_vars_dict, if_vars_dict, else_vars_dict,
                        after_ifelse_vars_dict):
      """
      Find out the ast.Name list of output by analyzing node's AST information.
      One of the following conditions should be satisfied while determining whether a variable is a return value:
      1. the var in parent scope is modified in If.body or If.orelse node.
      2. new var is both created in If.body and If.orelse node.
      3. new var is created only in one of If.body or If.orelse node, and it used as gast.Load firstly after gast.If node.
  
      For example:
          x, y = 5, 10
          if x > 4:
              x = x+1
              z = x*x
              q = 10
          else:
              y = y - 1
              z = y*y
              m = 20
              n = 20
  
          print(q)
          n = 30
          print(n)
  
  
      The return_ids are (x, y, z, q) for `If.body` and `If.orelse`node, because
      1. x is modified in If.body node,
      2. y is modified in If.body node,
      3. z is both created in If.body and If.orelse node,
      4. q is created only in If.body, and it is used by `print(q)` as gast.Load.
      Note:
          After transformed, q and z are created in parent scope. For example,
  
          x, y = 5, 10
          q = paddle.jit.dy2static.data_layer_not_check(name='q', shape=[-1], dtype='float32')
          z = paddle.jit.dy2static.data_layer_not_check(name='z', shape=[-1], dtype='float32')
  
          def true_func(x, y, q):
              x = x+1
              z = x*x
              q = 10
              return x,y,z,q
  
          def false_func(x, y, q):
              y = y - 1
              z = y*y
              m = 20
              n = 20
              return x,y,z,q
  
          x,y,z,q = fluid.layers.cond(x>4, lambda: true_func(x, y), lambda: false_func(x, y, q))
  
      m and n are not in return_ids, because
      5. m is created only in If.orelse, but it is not used after gast.If node.
      6. n is created only in If.orelse, and it is used by `n = 30` and `print(n)`, but it is not used as gast.Load firstly but gast.Store .
  
      """
  
      def _is_return_var(ctxs):
          for ctx in ctxs:
              if isinstance(ctx, (gast.Store, gast.Param)):
                  return True
          return False
  
      def _vars_with_store(ids_dict):
          vars = []
          for k, ctxs in six.iteritems(ids_dict):
              if _is_return_var(ctxs):
                  vars.append(k)
          return vars
  
      def _modified_vars(child_dict, parent_dict):
          return set([
              var for var in _vars_with_store(child_dict) if var in parent_dict
          ])
  
      def _vars_loaded(ids_dict):
          """
          gast.Param is also a kind of `load` semantic.
          """
          new_dict = defaultdict(list)
          for k, ctxs in six.iteritems(ids_dict):
              for ctx in ctxs:
                  if isinstance(ctx, (gast.Load, gast.Param)):
                      new_dict[k].append(ctx)
          return new_dict
  
      # modified vars
      body_modified_vars = _modified_vars(if_vars_dict, parent_vars_dict)
      orelse_modified_vars = _modified_vars(else_vars_dict, parent_vars_dict)
      modified_vars = body_modified_vars | orelse_modified_vars
  
      # new vars
      body_new_vars = set([
          var for var in _vars_with_store(if_vars_dict)
          if var not in parent_vars_dict
      ])
      orelse_new_vars = set([
          var for var in _vars_with_store(else_vars_dict)
          if var not in parent_vars_dict
      ])
      new_vars_in_body_or_orelse = body_new_vars | orelse_new_vars
      new_vars_in_one_of_body_or_orelse = body_new_vars ^ orelse_new_vars
  
      # 1. the var in parent scope is modified in If.body or If.orelse node.
      modified_vars_from_parent = modified_vars - new_vars_in_body_or_orelse
  
      # 2. new var is both created in If.body and If.orelse node.
      new_vars_in_body_and_orelse = body_new_vars & orelse_new_vars
  
      # 3. new var is created only in one of If.body or If.orelse node, and it used as gast.Load firstly after gast.If node.
      # TODO(zhhsplendid): the _vars_loaded can be optimized as _vars_loaded_before_store. Because if a variable is stored before load,
      # the value would change by the store statement, we don't have to return to change the value. However, analysis is
      # complex because if the IfElse is nested and outer IfElse store statement may not run at all. We will put this optimization
      # as the future TODO
      used_vars_after_ifelse = set(
          [var for var in _vars_loaded(after_ifelse_vars_dict)])
      new_vars_to_create = new_vars_in_one_of_body_or_orelse & used_vars_after_ifelse | new_vars_in_body_and_orelse
  
      # 4. generate return_ids of if/else node.
      return_ids = list(modified_vars_from_parent | new_vars_in_body_and_orelse |
                        new_vars_to_create)
      return_ids.sort()
  
      return return_ids, modified_vars_from_parent, new_vars_to_create
function_tokens: def parse_cond_return ( parent_vars_dict , if_vars_dict , else_vars_dict , after_ifelse_vars_dict ) : def _is_return_var ( ctxs ) : for ctx in ctxs : if isinstance ( ctx , ( gast . Store , gast . Param ) ) : return True return False def _vars_with_store ( ids_dict ) : vars = [ ] for k , ctxs in six . iteritems ( ids_dict ) : if _is_return_var ( ctxs ) : vars . append ( k ) return vars def _modified_vars ( child_dict , parent_dict ) : return set ( [ var for var in _vars_with_store ( child_dict ) if var in parent_dict ] ) def _vars_loaded ( ids_dict ) : """
          gast.Param is also a kind of `load` semantic.
          """ new_dict = defaultdict ( list ) for k , ctxs in six . iteritems ( ids_dict ) : for ctx in ctxs : if isinstance ( ctx , ( gast . Load , gast . Param ) ) : new_dict [ k ] . append ( ctx ) return new_dict # modified vars body_modified_vars = _modified_vars ( if_vars_dict , parent_vars_dict ) orelse_modified_vars = _modified_vars ( else_vars_dict , parent_vars_dict ) modified_vars = body_modified_vars | orelse_modified_vars # new vars body_new_vars = set ( [ var for var in _vars_with_store ( if_vars_dict ) if var not in parent_vars_dict ] ) orelse_new_vars = set ( [ var for var in _vars_with_store ( else_vars_dict ) if var not in parent_vars_dict ] ) new_vars_in_body_or_orelse = body_new_vars | orelse_new_vars new_vars_in_one_of_body_or_orelse = body_new_vars ^ orelse_new_vars # 1. the var in parent scope is modified in If.body or If.orelse node. modified_vars_from_parent = modified_vars - new_vars_in_body_or_orelse # 2. new var is both created in If.body and If.orelse node. new_vars_in_body_and_orelse = body_new_vars & orelse_new_vars # 3. new var is created only in one of If.body or If.orelse node, and it used as gast.Load firstly after gast.If node. # TODO(zhhsplendid): the _vars_loaded can be optimized as _vars_loaded_before_store. Because if a variable is stored before load, # the value would change by the store statement, we don't have to return to change the value. However, analysis is # complex because if the IfElse is nested and outer IfElse store statement may not run at all. We will put this optimization # as the future TODO used_vars_after_ifelse = set ( [ var for var in _vars_loaded ( after_ifelse_vars_dict ) ] ) new_vars_to_create = new_vars_in_one_of_body_or_orelse & used_vars_after_ifelse | new_vars_in_body_and_orelse # 4. generate return_ids of if/else node. return_ids = list ( modified_vars_from_parent | new_vars_in_body_and_orelse | new_vars_to_create ) return_ids . sort ( ) return return_ids , modified_vars_from_parent , new_vars_to_create