[GSoC] symbol to denote multiple operators

Richard Biener richard.guenther@gmail.com
Mon Jul 14 12:06:00 GMT 2014


On Fri, Jul 11, 2014 at 4:59 PM, Prathamesh Kulkarni
<bilbotheelffriend@gmail.com> wrote:
> On 7/11/14, Richard Biener <richard.guenther@gmail.com> wrote:
>> On Thu, Jul 10, 2014 at 8:05 PM, Prathamesh Kulkarni
>> <bilbotheelffriend@gmail.com> wrote:
>>> Hi,
>>>    I have attempted to add syntax for symbol to denote multiple
>>> operators.
>>>
>>> I tried it with few bogus patterns and it appears to work.... hopefully
>>> -:)
>>> eg: (bogus pattern):
>>> (for op in plus minus
>>>   (match_and_simplify
>>>     (op @0 @1)
>>>     (op @0 @0)))
>>>
>>> generates following patterns:
>>> (plus @0 @1) -> (plus @0 @0)  // simplify_0
>>> (plus @0 @1) -> (mult @0 @0)  // simplify_1
>>> (mult @0 @1) -> (plus @0 @0)  // simplify_2
>>> (mult @0 @1) -> (mult @0 @0)  // simplify_3
>>
>> s/mult/minus/?  I think it should only generate
>>
>>  (plus @0 @1) -> (plus @0 @0)
>>  (minus @0 @1) -> (minus @0 @0)
>>
>> to get the what you write we should need to write
>>
>>  (for op1 in plus minus
>>    (for op2 in plus minus
>>      (match_and_simplify
>>         (op1 @0 @1)
>>         (op2 @0 @0))))
>>
>>> root (0xab6b10), 0, 2
>>> |--(PLUS_EXPR) (0xab6b30), 1, 1
>>> |----true (0xab6ba0), 2, 1
>>> |------true (0xab6c10), 3, 2
>>> |--------simplify_0 { 0xab6ba0, 0xab6c10, (nil), (nil),  }  (0xab6c80), 4,
>>> 0
>>> |--------simplify_1 { 0xab6ba0, 0xab6c10, (nil), (nil),  }  (0xab6d40), 4,
>>> 0
>>> |--(MULT_EXPR) (0xab6d00), 1, 1
>>> |----true (0xab6d90), 2, 1
>>> |------true (0xab6e00), 3, 2
>>> |--------simplify_2 { 0xab6d90, 0xab6e00, (nil), (nil),  }  (0xab6e70), 4,
>>> 0
>>> |--------simplify_3 { 0xab6d90, 0xab6e00, (nil), (nil),  }  (0xab6f30), 4,
>>> 0
>>>
>>> * Changes to rest of the code:
>>> a) commutating patterns was interfering with this, because
>>> parse_match_and_simplify, immediately commutated match operand. Symbol
>>> should be replaced by operators before commutating. This required
>>> adjusting simplify (back to operand *match), and commutating is done
>>> in new function lower_commutative. Ideally this should be done during
>>> insertion in decision tree ?
>>
>> Yes, commutating should be done by inserting a pattern multiple
>> times with adjusted AST walk order.
>>
>>> b) adjustments required to e_operation constructor, so it doesn't
>>> call fatal, when it does not find id to be in the hash table.
>>
>> Eventually just temporarily insert a new operator in the hash table
>> when parsing comes along a (for OP ...?  That is, add a new kind,
>> USER and just re-use base->id?
>>
>>> * Caveats
>>> a) new e_operation constructor taking id_base * argument. Not sure
>>> if that's required.
>>> b) e_operation::user_id denotes user-defined identifier (<opname>),
>>> a rather apologetic name ...
>>> c) Similar to commutate(), replace_user_id() does not clone AST's.
>>> So we have multiple AST's sharing same nodes.
>>
>> I wonder if we want to parse the 'for' into an AST node instead,
>> thus not expand it on-the-fly.  Applying could then happen during
>> DT insertion.  Or as a separate lowering like you introduce
>> lower_commutative - that looks  cleaner.
>>
>> Or if we can simply parse the match-and-simplify multiple times, with
>> the for op replaces, using _cpp_backup_tokens.  Ok, no - that
>> sounds like too much of a hack.
>>
>>> * add multiple symbols ?
>>> should we have
>>> (for <opname> in operator-list1, <opname2> in operator-list2
>>>   (match_and_simplify
>>>      ...))
>>> or have nested for ?
>>> (for <opname> in operator-list1
>>>    (for <opname2> in operator-list2
>>>        (match_and_simplify
>>>           ....)))
>>
>> It depends on the desired semantics.  It's a lot clearer with
>> single opname for only (but then we eventually need nested for).
>>
>>> * we don't detect functions with wrong arguments
>>> for example, we dont give error on:
>>> (built_in_sqrt @0 @1)
>>> I guess that's because we don't have an easy way to figure out
>>> number of arguments a function expects ?
>>> (is there a built-in equivalent of tree_code_length[] ?)
>>
>> Yeah, the function stuff is still very simplistic and no, there isn't
>> any easy way of extracting the number of expected arguments
>> from builtins.def (it's encoded in the type).  The easiest way
>> would be to change builtins.def to add a number-of-args argument ...
>>
>> Let's just defer that issue.
>>
>>
>> As for the patch, we shouldn't do the cartesian_product - that's
>> hardly ever what the user intends and it means there isn't any
>> way of repeating the same pattern for multiple operators.
>>
>> A common use for 'for' would be (for OP in ne eq (...)) as most
>> equality foldings are valid for ne and eq.  Another is
>> for the various division kinds we have - trunc_div ceil_div floor_div
>> and round_div (same for mod):
>>
>> (for op in trunc_div ceil_div floor_div round_div
>>   (match_and_simplify
>>      (op @0 integer_onep)
>>      @0))
>>
>> (good example for match.pd to exercise the code)
>>
>> Can you fix the cartesian product thing (it should only simplify the
>> patch)?
> This version of the patch, removes cartesian_product, and reuses
> id_base::id for user-defined symbols.
>
> eg:
> (for op in plus minus
>   (match_and_simplify
>     (op (op @0 @1) @2)
>     (op @0 @0)))
>
> generates following patterns:
> (plus (plus @0 @1) @2) -> (plus @0 @0)
> (minus (minus @0 @1) @2) -> (minus @0 @0)
> Is this correct ?

Yes.

> I added the (for op in trunc_div floor_div ceil_div round_div ..)
> pattern in match.pd
> This works for trunc_div, I am not sure how to generate
> floor_div/ceil_div/round_div
> from C test-case.

Yeah, I think all of them may only appear with variable-length array
lowering.  No need to add testcases for them.

> I added the following rotate pattern in match.pd:
> /* (x << CNT1) OP (x >> CNT2) -> x r<< CNT1 OP being +, |, ^ */
> (for op in plus bit_ior bit_xor
> (match_and_simplify
>   (op:c (lshift @0 INTEGER_CST_P@1) (rshift @0 INTEGER_CST_P@2))
>   if (tree_fits_uhwi_p (@1) && tree_fits_uhwi_p (@2)
>       && tree_to_uhwi (@1) + tree_to_uhwi (@2) == TYPE_PRECISION (type))
>   (lrotate @0 @1)))
>
> Is this correct ?

it doesn't work for signed x (rshift is arithmetic shift).  So you miss
a TYPE_UNSIGNED (TREE_TYPE (@0)) check.  fold-const.c also
verifies that mode and type precision match (and makes sure to
use the vector/complex type element precision as shifts on
vectors shift their elements).  See around fold-const.c:10562.

I have fixed that, restricting it to integer types for now and committed
the patch.

Thanks,
Richard.

> * genmatch.c (id_base::id_kind): New enum value USER_DEFINED.
>     (e_operation::e_operation): Add default argument add_new_id.
>     (simplify): Remove member matchers.
>     (simplify): New member match.
>     (print_matches): Adjust to changes in simplify.
>     (decision_tree::insert): Likewise.
>     (parse_match_and_simplify): Likewise.
>     (lower_commutative): New function.
>     (check_operator): Likewise.
>     (replace_id): Likewise.
>     (eat_ident): Likewise.
>     (parse_for): Likewise.
>     (parse_expr): Call check_operator.
>     (main): Call parse_for, lower_commutative.
>
> * match.pd: Add pattern for div, and rotate pattern.
>
> [gcc/testsuite/gcc.dg/tree-ssa]
> * match-rotate.c: New test-case.
>
> Thanks and Regards,
> Prathamesh
>
>>
>> Thanks,
>> Richard.
>>
>>> * genmatch.c (e_operation::e_operation): New constructor.
>>> (e_operation::user_id): New member.
>>> (e_operation::get_op): New member function.
>>> (simplify::matchers): Remove.
>>> (simplify::match): New member.
>>> (lower_commutative): New function.
>>> (check_operator): Likewise.
>>> (replace_user_id): Likewise.
>>> (decision_tree::insert): Adjust to changes in simplify.
>>> (eat_ident): New function.
>>> (parse_expr): Call to check_operator.
>>> (parse_for): New function.
>>> (main): Add calls to parse_for, lower_commutative.
>>>
>>> Thanks and Regards,
>>> Prathamesh
>>



More information about the Gcc-patches mailing list