Expected behavior of calling bitcasted functions?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Expected behavior of calling bitcasted functions?

Matt Arsenault
Hi,

I'm not sure what the expected behavior of calling a bitcasted function is. Suppose you have a case like this (which you get on the source level from attribute alias):

@alias_f32 = alias bitcast (i32 (i32)* @func_i32 to float (float)*)

define internal i32 @func_i32(i32 %v) noinline nounwind {
entry:
  ret i32 %v
}

define void @bitcast_alias_scalar(float* noalias %source, float* noalias %dest) nounwind {
entry:
  %arrayidx = getelementptr float* %source, i32 0
  %tmp2 = load float* %arrayidx, align 8
  %call = call float @alias_f32(float %tmp2) nounwind
  %arrayidx8 = getelementptr float* %dest, i32 0
  store float %call, float* %arrayidx8, align 8
  ret void
}

If you run opt -instcombine on this, this transforms into
define void @bitcast_alias_scalar(float* noalias %source, float* noalias %dest) nounwind {
entry:
  %tmp2 = load float* %source, align 8
  %0 = fptoui float %tmp2 to i32
  %call = call i32 @func_i32(i32 %0) nounwind
  %1 = uitofp i32 %call to float
  store float %1, float* %dest, align 8
  ret void
}


Note the fptoui / uitofp conversions to the underlying function's argument / return type. I would expect this to bitcast the arguments and call the underlying function. This transformation happens in InstCombiner::transformConstExprCastCall. This kind of thing almost seems intentional though from some of the comments and tests, so I'm not sure what's supposed to be going on. A conversion that changes the bits doesn't make any sense to me.

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Expected behavior of calling bitcasted functions?

Pete Couperus
Hello,

This is an interesting example.  Whenever I see strange things like this, I use opt's -lint.
In this case, opt -lint reports:
Undefined behavior: Call return type mismatches callee return type
  %call = call float @alias_f32(float %tmp2) #1

You'll get a similar report when the parameter types mismatch.

Pete



On Wed, May 29, 2013 at 5:40 PM, Arsenault, Matthew <[hidden email]> wrote:
Hi,

I'm not sure what the expected behavior of calling a bitcasted function is. Suppose you have a case like this (which you get on the source level from attribute alias):

@alias_f32 = alias bitcast (i32 (i32)* @func_i32 to float (float)*)

define internal i32 @func_i32(i32 %v) noinline nounwind {
entry:
  ret i32 %v
}

define void @bitcast_alias_scalar(float* noalias %source, float* noalias %dest) nounwind {
entry:
  %arrayidx = getelementptr float* %source, i32 0
  %tmp2 = load float* %arrayidx, align 8
  %call = call float @alias_f32(float %tmp2) nounwind
  %arrayidx8 = getelementptr float* %dest, i32 0
  store float %call, float* %arrayidx8, align 8
  ret void
}

If you run opt -instcombine on this, this transforms into
define void @bitcast_alias_scalar(float* noalias %source, float* noalias %dest) nounwind {
entry:
  %tmp2 = load float* %source, align 8
  %0 = fptoui float %tmp2 to i32
  %call = call i32 @func_i32(i32 %0) nounwind
  %1 = uitofp i32 %call to float
  store float %1, float* %dest, align 8
  ret void
}


Note the fptoui / uitofp conversions to the underlying function's argument / return type. I would expect this to bitcast the arguments and call the underlying function. This transformation happens in InstCombiner::transformConstExprCastCall. This kind of thing almost seems intentional though from some of the comments and tests, so I'm not sure what's supposed to be going on. A conversion that changes the bits doesn't make any sense to me.

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev


_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Expected behavior of calling bitcasted functions?

Matt Arsenault
On 05/30/2013 06:12 AM, Pete Couperus wrote:
Hello,

This is an interesting example.  Whenever I see strange things like this, I use opt's -lint.
In this case, opt -lint reports:
Undefined behavior: Call return type mismatches callee return type
  %call = call float @alias_f32(float %tmp2) #1

You'll get a similar report when the parameter types mismatch.

Pete

Is it really supposed to be undefined? The tests are checking for specific behavior in these "undefined" cases.

opt -lint < test/Transforms/InstCombine/call.ll

Undefined behavior: Call argument type mismatches callee parameter type
  call  void bitcast (void (i8*)* @test1a to void (i32*)*)(i32* %A)
Undefined behavior: Call argument type mismatches callee parameter type
  call  void bitcast (void (i8)* @test2a to void (i32)*)(i32 %A)
Undefined behavior: Call return type mismatches callee return type
  %X = call  i32 bitcast (i8 ()* @test4a to i32 ()*)()
Undefined behavior: Call argument count mismatches callee argument count
  %X = call  i32 bitcast (i32 (i32)* @test6a to i32 ()*)()
Undefined behavior: Call argument count mismatches callee argument count
  call  void bitcast (void ()* @test7a to void (i32)*)(i32 5)


_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Expected behavior of calling bitcasted functions?

Pete Couperus
Hello,

Using a type incompatible pointer to call a function has undefined behavior (6.3.2.3).
As for the tests, I don't know...maybe we want specific behavior within LLVM for these cases?

Pete




On Thu, May 30, 2013 at 11:41 AM, Matt Arsenault <[hidden email]> wrote:
On 05/30/2013 06:12 AM, Pete Couperus wrote:
Hello,

This is an interesting example.  Whenever I see strange things like this, I use opt's -lint.
In this case, opt -lint reports:
Undefined behavior: Call return type mismatches callee return type
  %call = call float @alias_f32(float %tmp2) #1

You'll get a similar report when the parameter types mismatch.

Pete

Is it really supposed to be undefined? The tests are checking for specific behavior in these "undefined" cases.

opt -lint < test/Transforms/InstCombine/call.ll

Undefined behavior: Call argument type mismatches callee parameter type
  call  void bitcast (void (i8*)* @test1a to void (i32*)*)(i32* %A)
Undefined behavior: Call argument type mismatches callee parameter type
  call  void bitcast (void (i8)* @test2a to void (i32)*)(i32 %A)

Undefined behavior: Call return type mismatches callee return type
  %X = call  i32 bitcast (i8 ()* @test4a to i32 ()*)()
Undefined behavior: Call argument count mismatches callee argument count
  %X = call  i32 bitcast (i32 (i32)* @test6a to i32 ()*)()
Undefined behavior: Call argument count mismatches callee argument count
  call  void bitcast (void ()* @test7a to void (i32)*)(i32 5)



_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Reply | Threaded
Open this post in threaded view
|

Re: Expected behavior of calling bitcasted functions?

Duncan Sands
In reply to this post by Matt Arsenault
Hi Matthew,

On 30/05/13 02:40, Arsenault, Matthew wrote:

> Hi,
>
> I'm not sure what the expected behavior of calling a bitcasted function is. Suppose you have a case like this (which you get on the source level from attribute alias):
>
> @alias_f32 = alias bitcast (i32 (i32)* @func_i32 to float (float)*)
>
> define internal i32 @func_i32(i32 %v) noinline nounwind {
> entry:
>    ret i32 %v
> }
>
> define void @bitcast_alias_scalar(float* noalias %source, float* noalias %dest) nounwind {
> entry:
>    %arrayidx = getelementptr float* %source, i32 0
>    %tmp2 = load float* %arrayidx, align 8
>    %call = call float @alias_f32(float %tmp2) nounwind
>    %arrayidx8 = getelementptr float* %dest, i32 0
>    store float %call, float* %arrayidx8, align 8
>    ret void
> }
>
> If you run opt -instcombine on this, this transforms into
> define void @bitcast_alias_scalar(float* noalias %source, float* noalias %dest) nounwind {
> entry:
>    %tmp2 = load float* %source, align 8
>    %0 = fptoui float %tmp2 to i32
>    %call = call i32 @func_i32(i32 %0) nounwind
>    %1 = uitofp i32 %call to float
>    store float %1, float* %dest, align 8
>    ret void
> }
>
>
> Note the fptoui / uitofp conversions to the underlying function's argument / return type. I would expect this to bitcast the arguments and call the underlying function. This transformation happens in InstCombiner::transformConstExprCastCall. This kind of thing almost seems intentional though from some of the comments and tests, so I'm not sure what's supposed to be going on. A conversion that changes the bits doesn't make any sense to me.

I would also expect bitcast to be used here.  This may just be a bug.

Ciao, Duncan.

_______________________________________________
LLVM Developers mailing list
[hidden email]         http://llvm.cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev