This is an archive of the discontinued LLVM Phabricator instance.

[InstCombiner] Make LibCallSimplifier add extension attribute to ldexp arg.
ClosedPublic

Authored by jonpa on Nov 4 2020, 4:56 AM.

Details

Summary

When an exp2() or or pow() is replaced by a call to ldexp(), the second integer argument should have the signext or zeroext attribute set (depending
on the conversion instruction opcode preceding the original call).

This was discovered by the SystemZ multistage bot: http://lab.llvm.org:8011/#/builders/8, where wrong code resulted when this extension was not performed.

Diff Detail

Event Timeline

jonpa created this revision.Nov 4 2020, 4:56 AM
Herald added a project: Restricted Project. · View Herald TranscriptNov 4 2020, 4:56 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
jonpa requested review of this revision.Nov 4 2020, 4:56 AM

This doesn't look quite right to me. ldexp has a signed "int" argument, so you always must use the "sext" sign extension attribute on that argument.

[Note that transforming a pow (2.0, uitofp (...)) to an ldexp is only even valid if the unsigned integer type is smaller than 32 bits. But this seems to be handled correctly by getIntToFPVal.]

jonpa updated this revision to Diff 302847.Nov 4 2020, 7:56 AM

I see... Patch updated.

lebedev.ri requested changes to this revision.Nov 4 2020, 8:06 AM
lebedev.ri added a subscriber: lebedev.ri.

This doesn't look right to me.
This should be done elsewhere more generically.
See the rest of SimplifyLibCalls.cpp - we should simply annotate ldexp's args with appropriate signext attribue.

This revision now requires changes to proceed.Nov 4 2020, 8:06 AM
jonpa added a comment.Nov 4 2020, 8:20 AM

This doesn't look right to me.
This should be done elsewhere more generically.
See the rest of SimplifyLibCalls.cpp - we should simply annotate ldexp's args with appropriate signext attribue.

I find cases of "CI->addParamAttr(ArgNo, ...)", but I thought also the declaration of ldexp should as well have the signext attribute on the argument, not just on the call instruction operand. Or is that not needed? (clang emits it also on the prototype for a normal function, it seems). Passing the attributes like I did makes emitBinaryFloatFnCallHelper() add them to both 'Callee' and 'CI'...

jonpa added a comment.Nov 9 2020, 6:59 AM

ping

@lebedev.ri Thanks for review so far. Since this is keeping a SystemZ buildbot failing, I would appreciate some further advice here... thanks

ping

@lebedev.ri Thanks for review so far. Since this is keeping a SystemZ buildbot failing, I would appreciate some further advice here... thanks

Given a function declaration, (e.g. that @ldexp), will/should all calls agree how the argument should be extended?

jonpa added a comment.Nov 9 2020, 7:18 AM

ping

@lebedev.ri Thanks for review so far. Since this is keeping a SystemZ buildbot failing, I would appreciate some further advice here... thanks

Given a function declaration, (e.g. that @ldexp), will/should all calls agree how the argument should be extended?

I believe all calls to @ldexp should have the signext attribute. It is then up to the target to perform the sign extension if needed per the calling convention. The attribute is needed to inform the target what kind of extension should be performed (sign/zero).

ping

@lebedev.ri Thanks for review so far. Since this is keeping a SystemZ buildbot failing, I would appreciate some further advice here... thanks

Given a function declaration, (e.g. that @ldexp), will/should all calls agree how the argument should be extended?

I believe all calls to @ldexp should have the signext attribute.

Awesome.
So, can you try if the miscompile goes away if you manually annotate the @ldexp declaration in IR with said signext?

It is then up to the target to perform the sign extension if needed per the calling convention. The attribute is needed to inform the target what kind of extension should be performed (sign/zero).

I'm not sure whether the call instruction must match the declaration w.r.t. extension attributes. In the IR generated by clang, the two always match:

; Function Attrs: noinline nounwind optnone
define dso_local signext i32 @test(i32 signext %x) #0 {
entry:
  %x.addr = alloca i32, align 4
  store i32 %x, i32* %x.addr, align 4
  %0 = load i32, i32* %x.addr, align 4
  ret i32 %0
}

; Function Attrs: noinline nounwind optnone
define dso_local signext i32 @main() #0 {
entry:
  %retval = alloca i32, align 4
  store i32 0, i32* %retval, align 4
  %0 = load i32, i32* @a, align 4
  %call = call signext i32 @test(i32 signext %0)
  ret i32 %call
}

I'm not sure what is supposed to happen if the two do not match, this doesn't seem obvious from reading the IR specs ...

jonpa added a comment.Nov 9 2020, 8:09 AM

So, can you try if the miscompile goes away if you manually annotate the @ldexp declaration in IR with said signext?

It seems that it is enough to have either the signext on the call operand or in the declaration, for the extension to be emitted by the SystemZ backend.

So, can you try if the miscompile goes away if you manually annotate the @ldexp declaration in IR with said signext?

It seems that it is enough to have either the signext on the call operand or in the declaration, for the extension to be emitted by the SystemZ backend.

Great.
So back to my original idea - can we simply annotate the LibFunc_ldexp*'s argument with signext attribute?
@xbolva00 might be able to help.

jonpa added a comment.Nov 9 2020, 9:27 AM

So, can you try if the miscompile goes away if you manually annotate the @ldexp declaration in IR with said signext?

It seems that it is enough to have either the signext on the call operand or in the declaration, for the extension to be emitted by the SystemZ backend.

Great.
So back to my original idea - can we simply annotate the LibFunc_ldexp*'s argument with signext attribute?
@xbolva00 might be able to help.

Are we sure that this is generally acceptable despite the fact that clang emits the signext attribute in both places?

If so, I suppose we should do something like what is done in insertSinCosCall(), i.e. calling M->getOrInsertFunction() and build the call instead of calling emitBinaryFloatFnCall()? That doesn't seem simpler to me though than the current patch...

jonpa updated this revision to Diff 304234.Nov 10 2020, 9:25 AM

So back to my original idea - can we simply annotate the LibFunc_ldexp*'s argument with signext attribute?

Ah, now I think I finally understand what you mean... :-) I agree this seems much better... Patch updated.

lebedev.ri accepted this revision.Nov 10 2020, 9:29 AM

Yep, that is indeed what i was suggesting all along :)
LGTM, thank you.

This revision is now accepted and ready to land.Nov 10 2020, 9:29 AM