diff mbox

[cxx-conversion] RFC - Helper types for building GIMPLE

Message ID 516DBFBF.50608@google.com
State New
Headers show

Commit Message

Diego Novillo April 16, 2013, 9:16 p.m. UTC
Thanks for the feedback, folks.

I've removed the builder type and added some overloads to simplify the 
creation of gimple assignments.  I have only added exactly the functions 
I needed to simplify a bit of gcc/asan.c.  I plan to continue adding and 
tweaking as I change client code.

Some things to note:

- The builder type gave us some more abstraction that would be nice to 
put in gimple itself.  However, gimple is now a union and gimple_seq is 
just a typedef for gimple.  So, adding behaviour to them will need to 
wait until we convert gimple into a proper class.

- This variant does not yield as much code savings as the original one, 
but it can be improved once gimple is a proper class.

- I will continue working in trunk.  This is not something that can be 
easily done in a branch since I will be touching a whole bunch of client 
code and I expect to make incremental changes for the next little while.


Tested on x86_64.


2013-04-16  Diego Novillo  <dnovillo@google.com>

     * gimple.c (create_gimple_tmp): New.
     (get_expr_type): New.
     (build_assign): New.
     (build_type_cast): New.
     * gimple.h (enum ssa_mode): Define.
     (gimple_seq_set_location): New.
     * asan.c (build_check_stmt): Change some gimple_build_* calls
         to use build_assign and build_type_cast.

commit a9c165448358a920e5756881e016865a812a5d81
Author: Diego Novillo <dnovillo@google.com>
Date:   Tue Apr 16 14:29:09 2013 -0400

     Simplified GIMPLE IL builder functions.

+      gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
      }
    else
      t = shadow;

Comments

Richard Biener April 19, 2013, 11:30 a.m. UTC | #1
On Tue, 16 Apr 2013, Diego Novillo wrote:

> Thanks for the feedback, folks.
> 
> I've removed the builder type and added some overloads to simplify the
> creation of gimple assignments.  I have only added exactly the functions I
> needed to simplify a bit of gcc/asan.c.  I plan to continue adding and
> tweaking as I change client code.
> 
> Some things to note:
> 
> - The builder type gave us some more abstraction that would be nice to put in
> gimple itself.  However, gimple is now a union and gimple_seq is just a
> typedef for gimple.  So, adding behaviour to them will need to wait until we
> convert gimple into a proper class.
> 
> - This variant does not yield as much code savings as the original one, but it
> can be improved once gimple is a proper class.
> 
> - I will continue working in trunk.  This is not something that can be easily
> done in a branch since I will be touching a whole bunch of client code and I
> expect to make incremental changes for the next little while.
> 
> 
> Tested on x86_64.

Comments inoine below.


> 2013-04-16  Diego Novillo  <dnovillo@google.com>
> 
>     * gimple.c (create_gimple_tmp): New.
>     (get_expr_type): New.
>     (build_assign): New.
>     (build_type_cast): New.
>     * gimple.h (enum ssa_mode): Define.
>     (gimple_seq_set_location): New.
>     * asan.c (build_check_stmt): Change some gimple_build_* calls
>         to use build_assign and build_type_cast.
> 
> commit a9c165448358a920e5756881e016865a812a5d81
> Author: Diego Novillo <dnovillo@google.com>
> Date:   Tue Apr 16 14:29:09 2013 -0400
> 
>     Simplified GIMPLE IL builder functions.
> 
> diff --git a/gcc/gimple.c b/gcc/gimple.c
> index 8bd80c8..64f7b1a 100644
> --- a/gcc/gimple.c
> +++ b/gcc/gimple.c
> @@ -4207,4 +4207,105 @@ gimple_asm_clobbers_memory_p (const_gimple stmt)
> 
>    return false;
>  }
> +
> +
> +/* Create and return an unnamed temporary.  MODE indicates whether
> +   this should be an SSA or NORMAL temporary.  TYPE is the type to use
> +   for the new temporary.  */
> +
> +tree
> +create_gimple_tmp (tree type, enum ssa_mode mode)
> +{
> +  return (mode == M_SSA)
> +         ? make_ssa_name (type, NULL)
> +         : create_tmp_var (type, NULL);
> +}

Eh - what exactly is this for?  It doesn't simplify anything!

> +
> +/* 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.  */
> +
> +static tree
> +get_expr_type (enum tree_code code, tree op)
> +{
> +  return (TREE_CODE_CLASS (code) == tcc_comparison)
> +     ? boolean_type_node
> +     : TREE_TYPE (op);
> +}

Which returns wrong results for FIX_TRUNC_EXPR and a double op.
This function cannot be implemented correctly with the given
signature (read: the type of the expression cannot be determined
by just looking at 'code' and 'op' in all cases).  Drop it.

> +
> +/* Build a new gimple assignment.  The LHS of the assignment is a new
> +   temporary whose type matches the given expression.  MODE indicates
> +   whether the LHS should be an SSA or a normal temporary.  CODE is
> +   the expression code for the RHS.  OP1 is the first operand and VAL
> +   is an integer value to be used as the second operand.  */
> +
> +gimple
> +build_assign (enum tree_code code, tree op1, int val, enum ssa_mode mode)
> +{
> +  tree op2 = build_int_cst (TREE_TYPE (op1), val);
> +  tree lhs = create_gimple_tmp (get_expr_type (code, op1), mode);
> +  return gimple_build_assign_with_ops (code, lhs, op1, op2);
> +}

This 'mode' thingie is broken.  Make that beast auto-detected
(gimple_in_ssa_p && is_gimple_reg_type).

Why not start simple and continue my overloading patches
(which dropped gimple_build_assign_with_ops3) to make all the
gimple stmt builders overloads of a single

gimple_build_assing ()

?  Do it incrementally though, as I expect that with each new overload
one function goes away and users are adjusted.  That way you also
get testing coverage - which your patch has none.

> +gimple
> +build_assign (enum tree_code code, gimple g, int val, enum ssa_mode mode)
> +{
> +  return build_assign (code, gimple_assign_lhs (g), val, mode);
> +}
> +
> +
> +/* Build and return a new GIMPLE assignment.  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.  */
> +
> +gimple
> +build_assign (enum tree_code code, tree op1, tree op2, enum ssa_mode mode)
> +{
> +  tree lhs = create_gimple_tmp (get_expr_type (code, op1), mode);
> +  return gimple_build_assign_with_ops (code, lhs, op1, op2);
> +}
> +
> +gimple
> +build_assign (enum tree_code code, gimple op1, tree op2, enum ssa_mode mode)
> +{
> +  return build_assign (code, gimple_assign_lhs (op1), op2, mode);
> +}
> +
> +gimple
> +build_assign (enum tree_code code, tree op1, gimple op2, enum ssa_mode mode)
> +{
> +  return build_assign (code, op1, gimple_assign_lhs (op2), mode);
> +}
> +
> +gimple
> +build_assign (enum tree_code code, gimple op1, gimple op2, enum ssa_mode
> mode)
> +{
> +  return build_assign (code, gimple_assign_lhs (op1), gimple_assign_lhs
> (op2),
> +                       mode);
> +}
> +
> +/* Create and return a type cast assignment. This creates a NOP_EXPR
> +   that converts OP to TO_TYPE.  */
> +
> +gimple
> +build_type_cast (tree to_type, tree op, enum ssa_mode mode)
> +{
> +  tree lhs = create_gimple_tmp (to_type, mode);
> +  return gimple_build_assign_with_ops (NOP_EXPR, lhs, op, NULL_TREE);
> +}
> +
> +gimple
> +build_type_cast (tree to_type, gimple op, enum ssa_mode mode)
> +{
> +  return build_type_cast (to_type, gimple_assign_lhs (op), mode);
> +}

I'd say it should be

tree
gimple_convert (gimple_stmt_iterator *gsi, tree type, tree op)

which converts op to type, returning either 'op' (it's type is
compatible to 'type') or a new register temporary (please ICE
on !is_gimple_reg_type converts!) which initialization is
inserted at gsi (eventually needs an extra param for
the iterator update kind - unless we standardize on GSI_CONTINUE_LINKING
for all 'builders' which would make sense).

This gimple_convert should be used to replace all fold_convert
calls in the various passes (well, those that end up re-gimplifying
the result).

>  #include "gt-gimple.h"
> diff --git a/gcc/gimple.h b/gcc/gimple.h
> index 475d2ea..3a65e3c 100644
> --- a/gcc/gimple.h
> +++ b/gcc/gimple.h
> @@ -33,6 +33,15 @@ along with GCC; see the file COPYING3.  If not see
> 
>  typedef gimple gimple_seq_node;
> 
> +/* Types of supported temporaries.  GIMPLE temporaries may be symbols
> +   in normal form (i.e., regular decls) or SSA names.  This enum is
> +   used by create_gimple_tmp to tell it what kind of temporary the
> +   caller wants.  */
> +enum ssa_mode {
> +    M_SSA = 0,
> +    M_NORMAL
> +};
> +
>  /* For each block, the PHI nodes that need to be rewritten are stored into
>     these vectors.  */
>  typedef vec<gimple> gimple_vec;
> @@ -720,6 +729,17 @@ union GTY ((desc ("gimple_statement_structure (&%h)"),
> 
>  /* In gimple.c.  */
> 
> +/* Helper functions to build GIMPLE statements.  */
> +tree create_gimple_tmp (tree, enum ssa_mode = M_SSA);
> +gimple build_assign (enum tree_code, tree, int, enum ssa_mode = M_SSA);
> +gimple build_assign (enum tree_code, gimple, int, enum ssa_mode = M_SSA);
> +gimple build_assign (enum tree_code, tree, tree, enum ssa_mode = M_SSA);
> +gimple build_assign (enum tree_code, gimple, tree, enum ssa_mode = M_SSA);
> +gimple build_assign (enum tree_code, tree, gimple, enum ssa_mode = M_SSA);
> +gimple build_assign (enum tree_code, gimple, gimple, enum ssa_mode = M_SSA);
> +gimple build_type_cast (tree, tree, enum ssa_mode = M_SSA);
> +gimple build_type_cast (tree, gimple, enum ssa_mode = M_SSA);
> +
>  /* Offset in bytes to the location of the operand vector.
>     Zero if there is no operand vector for this tuple structure.  */
>  extern size_t const gimple_ops_offset_[];
> @@ -1096,7 +1116,6 @@ gimple_seq_empty_p (gimple_seq s)
>    return s == NULL;
>  }
> 
> -
>  void gimple_seq_add_stmt (gimple_seq *, gimple);
> 
>  /* Link gimple statement GS to the end of the sequence *SEQ_P.  If
> @@ -5326,4 +5345,15 @@ extern tree maybe_fold_or_comparisons (enum tree_code,
> tree, tree,
>                         enum tree_code, tree, tree);
> 
>  bool gimple_val_nonnegative_real_p (tree);
> +
> +
> +/* Set the location of all statements in SEQ to LOC.  */
> +
> +static inline void
> +gimple_seq_set_location (gimple_seq seq, location_t loc)
> +{
> +  for (gimple_stmt_iterator i = gsi_start (seq); !gsi_end_p (i); gsi_next
> (&i))
> +    gimple_set_location (gsi_stmt (i), loc);
> +}

Rather than this the gsi_insert_* routines accepting a sequence should
get an optional location argument?  OTOH the above is orthogonal to that.
Btw, the above should assert that we don't overwrite an existing
"good" location.

Richard.

>  #endif  /* GCC_GIMPLE_H */
> diff --git a/gcc/asan.c b/gcc/asan.c
> index 36eccf9..b8acaf7 100644
> --- a/gcc/asan.c
> +++ b/gcc/asan.c
> @@ -1380,57 +1380,23 @@ 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_seq seq = NULL;
> +      gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
> +      gimple_seq_add_stmt (&seq, shadow_test);
> +      gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, base_addr, 7));
> +      gimple_seq_add_stmt (&seq, build_type_cast (shadow_type,
> +                                                  gimple_seq_last (seq)));
>        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);
> +        gimple_seq_add_stmt (&seq,
> +                             build_assign (PLUS_EXPR, gimple_seq_last (seq),
> +                                           size_in_bytes - 1));
> +      gimple_seq_add_stmt (&seq, build_assign (GE_EXPR, gimple_seq_last
> (seq),
> +                                               shadow));
> +      gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
> +                                               gimple_seq_last (seq)));
> +      t = gimple_assign_lhs (gimple_seq_last (seq));
> +      gimple_seq_set_location (seq, location);
> +      gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
>      }
>    else
>      t = shadow;
> 
>
Diego Novillo April 24, 2013, 3:50 p.m. UTC | #2
On 2013-04-19 07:30 , Richard Biener wrote:
> On Tue, 16 Apr 2013, Diego Novillo wrote:
>
>> Thanks for the feedback, folks.
>>
>> I've removed the builder type and added some overloads to simplify the
>> creation of gimple assignments.  I have only added exactly the functions I
>> needed to simplify a bit of gcc/asan.c.  I plan to continue adding and
>> tweaking as I change client code.
>>
>> Some things to note:
>>
>> - The builder type gave us some more abstraction that would be nice to put in
>> gimple itself.  However, gimple is now a union and gimple_seq is just a
>> typedef for gimple.  So, adding behaviour to them will need to wait until we
>> convert gimple into a proper class.
>>
>> - This variant does not yield as much code savings as the original one, but it
>> can be improved once gimple is a proper class.
>>
>> - I will continue working in trunk.  This is not something that can be easily
>> done in a branch since I will be touching a whole bunch of client code and I
>> expect to make incremental changes for the next little while.
>>
>>
>> Tested on x86_64.
> Comments inoine below.
>
>
>> 2013-04-16  Diego Novillo  <dnovillo@google.com>
>>
>>      * gimple.c (create_gimple_tmp): New.
>>      (get_expr_type): New.
>>      (build_assign): New.
>>      (build_type_cast): New.
>>      * gimple.h (enum ssa_mode): Define.
>>      (gimple_seq_set_location): New.
>>      * asan.c (build_check_stmt): Change some gimple_build_* calls
>>          to use build_assign and build_type_cast.
>>
>> commit a9c165448358a920e5756881e016865a812a5d81
>> Author: Diego Novillo <dnovillo@google.com>
>> Date:   Tue Apr 16 14:29:09 2013 -0400
>>
>>      Simplified GIMPLE IL builder functions.
>>
>> diff --git a/gcc/gimple.c b/gcc/gimple.c
>> index 8bd80c8..64f7b1a 100644
>> --- a/gcc/gimple.c
>> +++ b/gcc/gimple.c
>> @@ -4207,4 +4207,105 @@ gimple_asm_clobbers_memory_p (const_gimple stmt)
>>
>>     return false;
>>   }
>> +
>> +
>> +/* Create and return an unnamed temporary.  MODE indicates whether
>> +   this should be an SSA or NORMAL temporary.  TYPE is the type to use
>> +   for the new temporary.  */
>> +
>> +tree
>> +create_gimple_tmp (tree type, enum ssa_mode mode)
>> +{
>> +  return (mode == M_SSA)
>> +         ? make_ssa_name (type, NULL)
>> +         : create_tmp_var (type, NULL);
>> +}
> Eh - what exactly is this for?  It doesn't simplify anything!

Helper for the other builders.  Should be private to gimple.c.

>
>> +
>> +/* 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.  */
>> +
>> +static tree
>> +get_expr_type (enum tree_code code, tree op)
>> +{
>> +  return (TREE_CODE_CLASS (code) == tcc_comparison)
>> +     ? boolean_type_node
>> +     : TREE_TYPE (op);
>> +}
> Which returns wrong results for FIX_TRUNC_EXPR and a double op.
> This function cannot be implemented correctly with the given
> signature (read: the type of the expression cannot be determined
> by just looking at 'code' and 'op' in all cases).  Drop it.

Hmm, yeah.  I will.

> This 'mode' thingie is broken.  Make that beast auto-detected
> (gimple_in_ssa_p && is_gimple_reg_type).

I don't like that.  This would make it context sensitive.  We should 
move away from these magic globals.

>
> Why not start simple and continue my overloading patches
> (which dropped gimple_build_assign_with_ops3) to make all the
> gimple stmt builders overloads of a single
>
> gimple_build_assing ()
>
> ?

That was kind of the idea.  But I started at a different place. I'll 
keep adding overloads and converting more client code.


>    Do it incrementally though, as I expect that with each new overload
> one function goes away and users are adjusted.  That way you also
> get testing coverage - which your patch has none.

Oh, it does.  All the asan tests exercise it.

> +/* Create and return a type cast assignment. This creates a NOP_EXPR
> +   that converts OP to TO_TYPE.  */
> +
> +gimple
> +build_type_cast (tree to_type, tree op, enum ssa_mode mode)
> +{
> +  tree lhs = create_gimple_tmp (to_type, mode);
> +  return gimple_build_assign_with_ops (NOP_EXPR, lhs, op, NULL_TREE);
> +}
> +
> +gimple
> +build_type_cast (tree to_type, gimple op, enum ssa_mode mode)
> +{
> +  return build_type_cast (to_type, gimple_assign_lhs (op), mode);
> +}
> I'd say it should be
>
> tree
> gimple_convert (gimple_stmt_iterator *gsi, tree type, tree op)
>
> which converts op to type, returning either 'op' (it's type is
> compatible to 'type') or a new register temporary (please ICE
> on !is_gimple_reg_type converts!) which initialization is
> inserted at gsi (eventually needs an extra param for
> the iterator update kind - unless we standardize on GSI_CONTINUE_LINKING
> for all 'builders' which would make sense).
>
> This gimple_convert should be used to replace all fold_convert
> calls in the various passes (well, those that end up re-gimplifying
> the result).

Why so many side-effects?  The reason I'm returning gimple is so that it 
can be used as an argument in more builders.  They use the LHS.

>
>>   bool gimple_val_nonnegative_real_p (tree);
>> +
>> +
>> +/* Set the location of all statements in SEQ to LOC.  */
>> +
>> +static inline void
>> +gimple_seq_set_location (gimple_seq seq, location_t loc)
>> +{
>> +  for (gimple_stmt_iterator i = gsi_start (seq); !gsi_end_p (i); gsi_next
>> (&i))
>> +    gimple_set_location (gsi_stmt (i), loc);
>> +}
> Rather than this the gsi_insert_* routines accepting a sequence should
> get an optional location argument?  OTOH the above is orthogonal to that.

Will do.


Diego.
diff mbox

Patch

diff --git a/gcc/gimple.c b/gcc/gimple.c
index 8bd80c8..64f7b1a 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -4207,4 +4207,105 @@  gimple_asm_clobbers_memory_p (const_gimple stmt)

    return false;
  }
+
+
+/* Create and return an unnamed temporary.  MODE indicates whether
+   this should be an SSA or NORMAL temporary.  TYPE is the type to use
+   for the new temporary.  */
+
+tree
+create_gimple_tmp (tree type, enum ssa_mode mode)
+{
+  return (mode == M_SSA)
+         ? make_ssa_name (type, NULL)
+         : create_tmp_var (type, NULL);
+}
+
+
+/* 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.  */
+
+static tree
+get_expr_type (enum tree_code code, tree op)
+{
+  return (TREE_CODE_CLASS (code) == tcc_comparison)
+     ? boolean_type_node
+     : TREE_TYPE (op);
+}
+
+
+/* Build a new gimple assignment.  The LHS of the assignment is a new
+   temporary whose type matches the given expression.  MODE indicates
+   whether the LHS should be an SSA or a normal temporary.  CODE is
+   the expression code for the RHS.  OP1 is the first operand and VAL
+   is an integer value to be used as the second operand.  */
+
+gimple
+build_assign (enum tree_code code, tree op1, int val, enum ssa_mode mode)
+{
+  tree op2 = build_int_cst (TREE_TYPE (op1), val);
+  tree lhs = create_gimple_tmp (get_expr_type (code, op1), mode);
+  return gimple_build_assign_with_ops (code, lhs, op1, op2);
+}
+
+gimple
+build_assign (enum tree_code code, gimple g, int val, enum ssa_mode mode)
+{
+  return build_assign (code, gimple_assign_lhs (g), val, mode);
+}
+
+
+/* Build and return a new GIMPLE assignment.  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.  */
+
+gimple
+build_assign (enum tree_code code, tree op1, tree op2, enum ssa_mode mode)
+{
+  tree lhs = create_gimple_tmp (get_expr_type (code, op1), mode);
+  return gimple_build_assign_with_ops (code, lhs, op1, op2);
+}
+
+gimple
+build_assign (enum tree_code code, gimple op1, tree op2, enum ssa_mode 
mode)
+{
+  return build_assign (code, gimple_assign_lhs (op1), op2, mode);
+}
+
+gimple
+build_assign (enum tree_code code, tree op1, gimple op2, enum ssa_mode 
mode)
+{
+  return build_assign (code, op1, gimple_assign_lhs (op2), mode);
+}
+
+gimple
+build_assign (enum tree_code code, gimple op1, gimple op2, enum 
ssa_mode mode)
+{
+  return build_assign (code, gimple_assign_lhs (op1), gimple_assign_lhs 
(op2),
+                       mode);
+}
+
+
+/* Create and return a type cast assignment. This creates a NOP_EXPR
+   that converts OP to TO_TYPE.  */
+
+gimple
+build_type_cast (tree to_type, tree op, enum ssa_mode mode)
+{
+  tree lhs = create_gimple_tmp (to_type, mode);
+  return gimple_build_assign_with_ops (NOP_EXPR, lhs, op, NULL_TREE);
+}
+
+gimple
+build_type_cast (tree to_type, gimple op, enum ssa_mode mode)
+{
+  return build_type_cast (to_type, gimple_assign_lhs (op), mode);
+}
+
  #include "gt-gimple.h"
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 475d2ea..3a65e3c 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -33,6 +33,15 @@  along with GCC; see the file COPYING3.  If not see

  typedef gimple gimple_seq_node;

+/* Types of supported temporaries.  GIMPLE temporaries may be symbols
+   in normal form (i.e., regular decls) or SSA names.  This enum is
+   used by create_gimple_tmp to tell it what kind of temporary the
+   caller wants.  */
+enum ssa_mode {
+    M_SSA = 0,
+    M_NORMAL
+};
+
  /* For each block, the PHI nodes that need to be rewritten are stored into
     these vectors.  */
  typedef vec<gimple> gimple_vec;
@@ -720,6 +729,17 @@  union GTY ((desc ("gimple_statement_structure (&%h)"),

  /* In gimple.c.  */

+/* Helper functions to build GIMPLE statements.  */
+tree create_gimple_tmp (tree, enum ssa_mode = M_SSA);
+gimple build_assign (enum tree_code, tree, int, enum ssa_mode = M_SSA);
+gimple build_assign (enum tree_code, gimple, int, enum ssa_mode = M_SSA);
+gimple build_assign (enum tree_code, tree, tree, enum ssa_mode = M_SSA);
+gimple build_assign (enum tree_code, gimple, tree, enum ssa_mode = M_SSA);
+gimple build_assign (enum tree_code, tree, gimple, enum ssa_mode = M_SSA);
+gimple build_assign (enum tree_code, gimple, gimple, enum ssa_mode = 
M_SSA);
+gimple build_type_cast (tree, tree, enum ssa_mode = M_SSA);
+gimple build_type_cast (tree, gimple, enum ssa_mode = M_SSA);
+
  /* Offset in bytes to the location of the operand vector.
     Zero if there is no operand vector for this tuple structure.  */
  extern size_t const gimple_ops_offset_[];
@@ -1096,7 +1116,6 @@  gimple_seq_empty_p (gimple_seq s)
    return s == NULL;
  }

-
  void gimple_seq_add_stmt (gimple_seq *, gimple);

  /* Link gimple statement GS to the end of the sequence *SEQ_P.  If
@@ -5326,4 +5345,15 @@  extern tree maybe_fold_or_comparisons (enum 
tree_code, tree, tree,
                         enum tree_code, tree, tree);

  bool gimple_val_nonnegative_real_p (tree);
+
+
+/* Set the location of all statements in SEQ to LOC.  */
+
+static inline void
+gimple_seq_set_location (gimple_seq seq, location_t loc)
+{
+  for (gimple_stmt_iterator i = gsi_start (seq); !gsi_end_p (i); 
gsi_next (&i))
+    gimple_set_location (gsi_stmt (i), loc);
+}
+
  #endif  /* GCC_GIMPLE_H */
diff --git a/gcc/asan.c b/gcc/asan.c
index 36eccf9..b8acaf7 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -1380,57 +1380,23 @@  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_seq seq = NULL;
+      gimple shadow_test = build_assign (NE_EXPR, shadow, 0);
+      gimple_seq_add_stmt (&seq, shadow_test);
+      gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, base_addr, 
7));
+      gimple_seq_add_stmt (&seq, build_type_cast (shadow_type,
+                                                  gimple_seq_last (seq)));
        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);
+        gimple_seq_add_stmt (&seq,
+                             build_assign (PLUS_EXPR, gimple_seq_last 
(seq),
+                                           size_in_bytes - 1));
+      gimple_seq_add_stmt (&seq, build_assign (GE_EXPR, gimple_seq_last 
(seq),
+                                               shadow));
+      gimple_seq_add_stmt (&seq, build_assign (BIT_AND_EXPR, shadow_test,
+                                               gimple_seq_last (seq)));
+      t = gimple_assign_lhs (gimple_seq_last (seq));
+      gimple_seq_set_location (seq, location);