This is an archive of the discontinued LLVM Phabricator instance.

Added InstCombine transform for pattern " ((X % Z) + (Y % Z)) % Z -> (X + Y) % Z ".
Needs ReviewPublic

Authored by ankur29.garg on Sep 15 2014, 3:38 AM.

Details

Summary

Hi Eveyone,

This patch implements the following transformation

" ((X % Z) + (Y % Z)) % Z -> (X + Y) % Z "

Please help in reviewing it.

Regards,
Ankur.

Diff Detail

Event Timeline

ankur29.garg retitled this revision from to Added InstCombine transform for pattern " ((X % Z) + (Y % Z)) % Z -> (X + Y) % Z "..
ankur29.garg updated this object.
ankur29.garg edited the test plan for this revision. (Show Details)
ankur29.garg set the repository for this revision to rL LLVM.
ankur29.garg added a subscriber: Unknown Object (MLST).
nlopes added a subscriber: nlopes.Sep 15 2014, 4:50 AM

This patch is incorrect:

$ ./alive.py < a.opt

Optimization: 1
Precondition: true
%1 = srem %x, %z
%2 = srem %y, %z
%3 = add %1, %2
%r = srem %3, %z

=>

%6 = add %x, %y
%r = srem %6, %z

Done: 1
ERROR: Domain of definedness of Target is smaller than Source's for i2 %r

Example:
%x i2 = 1 (0x1)
%z i2 = 3 (0x3)
%1 i2 = 0 (0x0)
%y i2 = 1 (0x1)
%2 i2 = 0 (0x0)
%3 i2 = 0 (0x0)
%6 i2 = 2 (0x2)
Source value: 0 (0x0)
Target value: undef

Meaning that the optimized code is introducing undefined behaviour
where the original code didn't have.

Nuno

Citando Ankur Garg <ankur29.garg@samsung.com>:

Hi majnemer, suyog, dexonsmith,

Hi Eveyone,

This patch implements the following transformation

" ((X % Z) + (Y % Z)) % Z -> (X + Y) % Z "

Please help in reviewing it.

Regards,
Ankur.

http://reviews.llvm.org/D5351

Files:

lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
test/Transforms/InstCombine/rem.ll

Thanks nlopes for the comments.
I think the tranformation only works for cases in which the addition doesn't overflow. I will add that check and resubmit the patch.

Thanks.

Hi nlopes,
I have modified it to check for the cases in which the addition overflows. The check is only valid when the operands or some their bits are known prior to the calculation, though. The transformation won't work for the cases in which the operands are completely unknown. I have included the test cases with both cases - one in which the addition overflows and another one in which it doesn't.
I think it can't be extended to the cases where the operands are completely variables because it is not possible to figure out whether their addition will overflow or not.
Please suggest if there is any other way to handle the cases for variable operands.

Thanks.
Regards,
Ankur Garg

majnemer added inline comments.Sep 17 2014, 11:47 AM
lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
1338–1340

Why are you mutating the LHS of I? This is unsafe if it has any other users.

test/Transforms/InstCombine/rem.ll
229–243

You don't have any CHECK statements here.

Hi David,
I have made the changes as per your comments. I have made sure that the I isn't mutated and also added CHECK statements for the test cases.
Please review the updated revision.

Thanks.

nlopes added a comment.EditedOct 11 2014, 2:58 AM

Sorry, still not correct:

Pre: WillNotOverflowSignedAdd(%x, %y)
%1 = srem %x, %z
%2 = srem %y, %z
%3 = add %1, %2
%r = srem %3, %z
  =>
%6 = add %x, %y
%r = srem %6, %z

Done: 1
ERROR: Domain of definedness of Target is smaller than Source's for i2 %r

Example:
%x i2 = 3 (0x3)
%z i2 = 3 (0x3)
%y i2 = 3 (0x3)
%1 i2 = 0 (0x0)
%2 i2 = 0 (0x0)
%3 i2 = 0 (0x0)
%6 i2 = 2 (0x2)
Source value: 0 (0x0)
Target value: undef

Hi nlopes,
Thanks for reviewing the patch.

In the example you have stated,

%x i2 = 3

since we are talking about signed integers, that is equivalent to %x i2 = -1

Similarly, %y i2 = -1 and %z i2 = -1.

I am not sure how [%6 = add %x, %y] calculates to [%6 i2 = 2]. Shouldn't it be [%6 i2 = -2] ?

Please clarify.
Thanks.

Hi nlopes,
Thanks for reviewing the patch.

In the example you have stated,

%x i2 = 3

since we are talking about signed integers, that is equivalent to %x i2 = -1

Similarly, %y i2 = -1 and %z i2 = -1.

I am not sure how [%6 = add %x, %y] calculates to [%6 i2 = 2]. Shouldn't it be [%6 i2 = -2] ?

Please clarify.
Thanks.

I think our output is now slightly better:

Example:
%x i4 = 0xC (12, -4)
%z i4 = 0xF (15, -1)
%y i4 = 0xC (12, -4)
%1 i4 = 0x0 (0)
%2 i4 = 0x0 (0)
%3 i4 = 0x0 (0)
%6 i4 = 0x8 (8, -8)
Source value: 0x0 (0)
Target value: undef

The idea is that %6 is INT_MIN and %z=-1. And so we get 'srem INT_MIN, -1', which is undefined behavior per the manual (http://llvm.org/docs/LangRef.html#srem-instruction).

Thanks for clarifying that. I understand now, what that undefined behavior is for.

Another thing, in these examples, all three inputs, %x, %y, & %z are known. That is, they are constants. I think such cases wouldn't make it to the transformation. When I was testing the transformation, I tested it with these inputs, the part of the code where the transformation takes place was never reached.
The transformation is useful only when some (or all) bits of any of these inputs are unknown. Otherwise, direct calculation of the expression is done. So, there should be no change in the behavior for the above input, as, in case of this input, this transformation will never be applied.

Thanks.

Thanks for clarifying that. I understand now, what that undefined behavior is for.

Another thing, in these examples, all three inputs, %x, %y, & %z are known. That is, they are constants. I think such cases wouldn't make it to the transformation. When I was testing the transformation, I tested it with these inputs, the part of the code where the transformation takes place was never reached.
The transformation is useful only when some (or all) bits of any of these inputs are unknown. Otherwise, direct calculation of the expression is done. So, there should be no change in the behavior for the above input, as, in case of this input, this transformation will never be applied.

Thanks.

So the counterexample shows concrete, constant, values, yes. But that doesn't mean that you need to have these constants in the IR.
This counterexample means that if you do this transformation, and if at run time, it happens that %x,%y,%z have the values that I've given you previously, then the program would execute undefined behavior. For example, if a subsequent optimization pass folds all %x,%y,%z to the constants I gave you, it will detect the undefined behavior and it can then remove all the code.
So, the optimization you're proposing introduces undefined behavior for one particular input (of %x,%y,%z) where the original code had defined behavior. Therefore the transformation is not safe.

Oh, thanks for clarifying that. I will work on the comments and resubmit the transformation.

Thanks.

dexonsmith resigned from this revision.Aug 25 2019, 8:22 AM