[PATCH] PR19958 wrong code at -O1 and above on x86_64-linux-gnu (InstCombine)
Duncan P. N. Exon Smith
dexonsmith at apple.com
Thu Jul 3 07:58:10 PDT 2014
> On 2014 Jul 3, at 00:07, Duncan P. N. Exon Smith <dexonsmith at apple.com> wrote:
>
>> On 2014 Jul 2, at 14:33, Sanjay Patel <spatel at rotateright.com> wrote:
>>
>> Sorry for the delay. LGTM...but considering that versions of this patch have caused miscompiles twice and I'm pretty new here, I think we should have someone with more instcombine experience give final approval in case I've missed anything.
>>
>> http://reviews.llvm.org/D4068
>>
>
> Hi Suyog,
>
> It seems like you might be able to go a little further without much
> work.
After thinking about it overnight, I think if you reverse the order of
the lg and divide, you'll avoid the expensive division. As a bonus, it
looks to me like you can always combine the instructions if you do this
carefully.
I.e., here's some pseudo-code for `ashr`:
// (icmp eq/ne (ashr exact C2, A), C1)
APInt C1, C2;
if (matchesAShrExact(..., C1, C2)) {
if (!C1) {
if (!C2)
return "i1 1";
return "i1 0";
}
if (!C2)
return "i1 0";
if (C1 == C2)
return "icmp eq A, 0";
if (C1.isNegative() != C2.isNegative())
return "i1 0";
if (C1.isNegative()) {
C1 = -C1;
C2 = -C2;
}
if (C1 > C2)
return "i1 0";
int LgC1 = C1.logBase2(),
LgC2 = C2.logBase2();
if (LgC1 == LgC2)
return "i1 0";
assert(LgC2 > LgC1);
// This subtraction takes the place of your original division.
int Shift = LgC2 - LgC1;
if (C1.shl(Shift) == C2)
return "icmp eq A, {Shift}";
return "i1 0";
}
I think other than the handling of `isNegative()`, the same logic works
for `lshr`.
I think you can use the same basic logic for non-`exact` right-shifts as
well. I believe you just need to modify the initial 0-related checks
and reverse the direction of the shift, effectively masking out the
lower bits of C2 in the comparison at the end:
// (icmp eq/ne (ashr C2, A), C1)
APInt C1, C2;
if (matchesAShrNotExact(..., C1, C2)) {
if (!C1) {
// Corner cases for C1 == 0 are different.
if (!C2)
return "i1 1";
if (C2.isNegative())
return "i1 0";
int Shift = C2.logBase2();
return "icmp gt A, {Shift};
}
if (!C2)
return "i1 0";
// ... same code as before, until:
// Use lshr here, since we've canonicalized to +ve numbers.
int Shift = LgC2 - LgC1;
if (C1 == C2.lshr(Shift))
return "icmp eq A, {Shift}";
return "i1 0";
}
Again, I think that aside from negative checking, the same basic logic
works for `lshr`.
More information about the llvm-commits
mailing list