Nice -- GCC LOC will be significantly reduced with these interfaces.

Using 'add' as interface name can be confusing -- new, or new_stmt, or
new_assignment/new_call etc might be better -- but we can delay the
bike shedding later.

David

On Wed, Mar 13, 2013 at 2:55 PM, Diego Novillo <dnovi...@google.com> wrote:
> This patch adds an initial implementation for a new helper type for
> generating GIMPLE statements.
>
> The type is called gimple_builder.  There are two main variants:
> gimple_builder_normal and gimple_builder_ssa.  The difference between
> the two is the temporaries they create.  The 'normal' builder creates
> temporaries in normal form (i.e., VAR_DECLs).  The 'ssa' builder
> creates SSA names.
>
> The basic functionality is described in
> http://gcc.gnu.org/wiki/cxx-conversion/gimple-generation.  I expect it
> to evolve as I address feedback on this initial implementation.
>
> The patch implements the initial builder.  It has enough functionality
> to simplify the generation of 3 address assignments (the bulk of all
> generated code).
>
> To use the builder:
>
> 1- Declare an instance 'gb' of gimple_builder_normal or
>    gimple_builder_ssa.  E.g., gimple_builder_ssa gb;
>
> 2- Use gb.add_* to add a new statement to it.  This
>    returns an SSA name or VAR_DECL with the value of the added
>    statement.
>
> 3- Call gb.insert_*() to insert the sequence of statements in the
>    builder into a statement iterator.
>
> For instance, in asan.c we generate the expression:
>
> (shadow != 0) & (base_addr & 7) + (size_in_bytes - 1)) >= shadow).
>
> with the following code:
>
> -----------------------------------------------------------------------------
>       gimple_builder_ssa gb(location);
>       t = gb.add (NE_EXPR, shadow, 0);
>       tree t1 = gb.add (BIT_AND_EXPR, base_addr, 7);
>       t1 = gb.add_type_cast (shadow_type, t1);
>       if (size_in_bytes > 1)
>         t1 = gb.add (PLUS_EXPR, t1, size_in_bytes - 1);
>       t1 = gb.add (GE_EXPR, t1, shadow);
>       t = gb.add (BIT_AND_EXPR, t, t1);
>       gb.insert_after (&gsi, GSI_NEW_STMT);
> -----------------------------------------------------------------------------
>
>
> In contrast, the original code needed to generate the same expression
> is significantly longer:
>
>
> -----------------------------------------------------------------------------
>       g = gimple_build_assign_with_ops (NE_EXPR,
>                                         make_ssa_name (boolean_type_node,
>                                                        NULL),
>                                         shadow,
>                                         build_int_cst (shadow_type, 0));
>       gimple_set_location (g, location);
>       gsi_insert_after (&gsi, g, GSI_NEW_STMT);
>       t = gimple_assign_lhs (g);
>
>       g = gimple_build_assign_with_ops (BIT_AND_EXPR,
>                                         make_ssa_name (uintptr_type,
>                                                        NULL),
>                                         base_addr,
>                                         build_int_cst (uintptr_type, 7));
>       gimple_set_location (g, location);
>       gsi_insert_after (&gsi, g, GSI_NEW_STMT);
>
>       g = gimple_build_assign_with_ops (NOP_EXPR,
>                                         make_ssa_name (shadow_type,
>                                                        NULL),
>                                         gimple_assign_lhs (g), NULL_TREE);
>       gimple_set_location (g, location);
>       gsi_insert_after (&gsi, g, GSI_NEW_STMT);
>       if (size_in_bytes > 1)
>         {
>           g = gimple_build_assign_with_ops (PLUS_EXPR,
>                                             make_ssa_name (shadow_type,
>                                                            NULL),
>                                             gimple_assign_lhs (g),
>                                             build_int_cst (shadow_type,
>                                                            size_in_bytes - 
> 1));
>           gimple_set_location (g, location);
>           gsi_insert_after (&gsi, g, GSI_NEW_STMT);
>         }
>
>       g = gimple_build_assign_with_ops (GE_EXPR,
>                                         make_ssa_name (boolean_type_node,
>                                                        NULL),
>                                         gimple_assign_lhs (g),
>                                         shadow);
>       gimple_set_location (g, location);
>       gsi_insert_after (&gsi, g, GSI_NEW_STMT);
>
>       g = gimple_build_assign_with_ops (BIT_AND_EXPR,
>                                         make_ssa_name (boolean_type_node,
>                                                        NULL),
>                                         t, gimple_assign_lhs (g));
>       gimple_set_location (g, location);
>       gsi_insert_after (&gsi, g, GSI_NEW_STMT);
>       t = gimple_assign_lhs (g);
> -----------------------------------------------------------------------------
>
> I expect to add more facilities to the builder.  Mainly, generation of
> control flow altering statements which will automatically reflect on
> the CFG.
>
> I do not think the helper should replace all code generation, but it
> should serve as a shorter/simpler way of generating GIMPLE IL in the
> common cases.
>
> Feedback welcome.  I would like to consider adding this facility when
> stage 1 opens.
>
> In the meantime, I've committed the patch to the cxx-conversion
> branch.
>
>
> Thanks.  Diego.
>
> diff --git a/gcc/asan.c b/gcc/asan.c
> index af9c01e..571882a 100644
> --- a/gcc/asan.c
> +++ b/gcc/asan.c
> @@ -1379,57 +1379,15 @@ build_check_stmt (location_t location, tree base, 
> gimple_stmt_iterator *iter,
>        /* Slow path for 1, 2 and 4 byte accesses.
>          Test (shadow != 0)
>               & ((base_addr & 7) + (size_in_bytes - 1)) >= shadow).  */
> -      g = gimple_build_assign_with_ops (NE_EXPR,
> -                                       make_ssa_name (boolean_type_node,
> -                                                      NULL),
> -                                       shadow,
> -                                       build_int_cst (shadow_type, 0));
> -      gimple_set_location (g, location);
> -      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
> -      t = gimple_assign_lhs (g);
> -
> -      g = gimple_build_assign_with_ops (BIT_AND_EXPR,
> -                                       make_ssa_name (uintptr_type,
> -                                                      NULL),
> -                                       base_addr,
> -                                       build_int_cst (uintptr_type, 7));
> -      gimple_set_location (g, location);
> -      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
> -
> -      g = gimple_build_assign_with_ops (NOP_EXPR,
> -                                       make_ssa_name (shadow_type,
> -                                                      NULL),
> -                                       gimple_assign_lhs (g), NULL_TREE);
> -      gimple_set_location (g, location);
> -      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
> -
> +      gimple_builder_ssa gb(location);
> +      t = gb.add (NE_EXPR, shadow, 0);
> +      tree t1 = gb.add (BIT_AND_EXPR, base_addr, 7);
> +      t1 = gb.add_type_cast (shadow_type, t1);
>        if (size_in_bytes > 1)
> -       {
> -         g = gimple_build_assign_with_ops (PLUS_EXPR,
> -                                           make_ssa_name (shadow_type,
> -                                                          NULL),
> -                                           gimple_assign_lhs (g),
> -                                           build_int_cst (shadow_type,
> -                                                          size_in_bytes - 
> 1));
> -         gimple_set_location (g, location);
> -         gsi_insert_after (&gsi, g, GSI_NEW_STMT);
> -       }
> -
> -      g = gimple_build_assign_with_ops (GE_EXPR,
> -                                       make_ssa_name (boolean_type_node,
> -                                                      NULL),
> -                                       gimple_assign_lhs (g),
> -                                       shadow);
> -      gimple_set_location (g, location);
> -      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
> -
> -      g = gimple_build_assign_with_ops (BIT_AND_EXPR,
> -                                       make_ssa_name (boolean_type_node,
> -                                                      NULL),
> -                                       t, gimple_assign_lhs (g));
> -      gimple_set_location (g, location);
> -      gsi_insert_after (&gsi, g, GSI_NEW_STMT);
> -      t = gimple_assign_lhs (g);
> +       t1 = gb.add (PLUS_EXPR, t1, size_in_bytes - 1);
> +      t1 = gb.add (GE_EXPR, t1, shadow);
> +      t = gb.add (BIT_AND_EXPR, t, t1);
> +      gb.insert_after (&gsi, GSI_NEW_STMT);
>      }
>    else
>      t = shadow;
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index 785c2f0..c4687df 100644
> --- a/gcc/gimple.c
> +++ b/gcc/gimple.c
> @@ -4210,4 +4210,115 @@ gimple_asm_clobbers_memory_p (const_gimple stmt)
>
>    return false;
>  }
> +
> +
> +/* Return the expression type to use based on the CODE and type of
> +   the given operand OP.  If the expression CODE is a comparison,
> +   the returned type is boolean_type_node.  Otherwise, it returns
> +   the type of OP.  */
> +
> +tree
> +gimple_builder_base::get_expr_type (enum tree_code code, tree op)
> +{
> +  return (TREE_CODE_CLASS (code) == tcc_comparison)
> +        ? boolean_type_node
> +        : TREE_TYPE (op);
> +}
> +
> +
> +/* Add a new assignment to this GIMPLE sequence.  The assignment has
> +   the form: GIMPLE_ASSIGN <CODE, LHS, OP1, OP2>. Returns LHS.  */
> +
> +tree
> +gimple_builder_base::add (enum tree_code code, tree lhs, tree op1, tree op2)
> +{
> +  gimple s = gimple_build_assign_with_ops (code, lhs, op1, op2);
> +  gimple_seq_add_stmt (&seq_, s);
> +  return lhs;
> +}
> +
> +
> +/* Add a new assignment to this GIMPLE sequence.  The new assignment will
> +   have the opcode CODE and operands OP1 and OP2.  The type of the
> +   expression on the RHS is inferred to be the type of OP1.
> +
> +   The LHS of the statement will be an SSA name or a GIMPLE temporary
> +   in normal form depending on the type of builder invoking this
> +   function.  */
> +
> +tree
> +gimple_builder_base::add (enum tree_code code, tree op1, tree op2)
> +{
> +  tree lhs = create_lhs_for_assignment (get_expr_type (code, op1));
> +  return add (code, lhs, op1, op2);
> +}
> +
> +
> +/* Add a new assignment to this GIMPLE sequence.  The new
> +   assignment will have the opcode CODE and operands OP1 and VAL.
> +   VAL is converted into a an INTEGER_CST of the same type as OP1.
> +
> +   The LHS of the statement will be an SSA name or a GIMPLE temporary
> +   in normal form depending on the type of builder invoking this
> +   function.  */
> +
> +tree
> +gimple_builder_base::add (enum tree_code code, tree op1, int val)
> +{
> +  tree type = get_expr_type (code, op1);
> +  tree op2 = build_int_cst (TREE_TYPE (op1), val);
> +  tree lhs = create_lhs_for_assignment (type);
> +  return add (code, lhs, op1, op2);
> +}
> +
> +
> +/* Add a type cast assignment to this GIMPLE sequence. This creates a 
> NOP_EXPR
> +   that converts OP to TO_TYPE.  Return the LHS of the generated assignment. 
>  */
> +
> +tree
> +gimple_builder_base::add_type_cast (tree to_type, tree op)
> +{
> +  tree lhs = create_lhs_for_assignment (to_type);
> +  return add (NOP_EXPR, lhs, op, NULL_TREE);
> +}
> +
> +
> +/* Insert this sequence after the statement pointed-to by iterator I.
> +   MODE is an is gs_insert_after.  Scan the statements in SEQ for new
> +   operands.  */
> +
> +void
> +gimple_builder_base::insert_after (gimple_stmt_iterator *i,
> +                                  enum gsi_iterator_update mode)
> +{
> +  /* Since we are inserting a sequence, the semantics for GSI_NEW_STMT
> +     are not quite what the caller is expecting.  GSI_NEW_STMT will
> +     leave the iterator pointing to the *first* statement of this
> +     sequence.  Rather, we want the iterator to point to the *last*
> +     statement in the sequence.  Therefore, we use
> +     GSI_CONTINUE_LINKING when GSI_NEW_STMT is requested.  */
> +  if (mode == GSI_NEW_STMT)
> +    mode = GSI_CONTINUE_LINKING;
> +  gsi_insert_seq_after (i, seq_, mode);
> +}
> +
> +
> +/* Create a GIMPLE temporary type TYPE to be used as the LHS of an
> +   assignment.  */
> +
> +tree
> +gimple_builder_normal::create_lhs_for_assignment (tree type)
> +{
> +  return create_tmp_var (type, NULL);
> +}
> +
> +
> +/* Create an SSA name of type TYPE to be used as the LHS of an assignment.  
> */
> +
> +tree
> +gimple_builder_ssa::create_lhs_for_assignment (tree type)
> +{
> +  return make_ssa_name (type, NULL);
> +}
> +
>  #include "gt-gimple.h"
> diff --git a/gcc/gimple.h b/gcc/gimple.h
> index 204c3c9..7b5e741 100644
> --- a/gcc/gimple.h
> +++ b/gcc/gimple.h
> @@ -5393,4 +5393,57 @@ extern tree maybe_fold_or_comparisons (enum tree_code, 
> tree, tree,
>                                        enum tree_code, tree, tree);
>
>  bool gimple_val_nonnegative_real_p (tree);
> +
> +
> +/* GIMPLE builder class.  This type provides a simplified interface
> +   for generating new GIMPLE statements.  */
> +
> +class gimple_builder_base
> +{
> +public:
> +  tree add (enum tree_code, tree, tree);
> +  tree add (enum tree_code, tree, int);
> +  tree add (enum tree_code, tree, tree, tree);
> +  tree add_type_cast (tree, tree);
> +  void insert_after (gimple_stmt_iterator *, enum gsi_iterator_update);
> +
> +protected:
> +  gimple_builder_base() : seq_(NULL), loc_(UNKNOWN_LOCATION) {}
> +  gimple_builder_base(location_t l) : seq_(NULL), loc_(l) {}
> +  tree get_expr_type (enum tree_code code, tree op);
> +  virtual tree create_lhs_for_assignment (tree) = 0;
> +
> +private:
> +  gimple_seq seq_;
> +  location_t loc_;
> +};
> +
> +
> +/* GIMPLE builder class for statements in normal form.  Statements generated
> +   by instances of this class will produce non-SSA temporaries.  */
> +
> +class gimple_builder_normal : public gimple_builder_base
> +{
> +public:
> +  gimple_builder_normal() : gimple_builder_base() {}
> +  gimple_builder_normal(location_t l) : gimple_builder_base(l) {}
> +
> +protected:
> +  virtual tree create_lhs_for_assignment (tree);
> +};
> +
> +
> +/* GIMPLE builder class for statements in normal form.  Statements generated
> +   by instances of this class will produce SSA names.  */
> +
> +class gimple_builder_ssa : public gimple_builder_base
> +{
> +public:
> +  gimple_builder_ssa() : gimple_builder_base() {}
> +  gimple_builder_ssa(location_t l) : gimple_builder_base(l) {}
> +
> +protected:
> +  virtual tree create_lhs_for_assignment (tree);
> +};
> +
>  #endif  /* GCC_GIMPLE_H */

Reply via email to