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