Why function pointer is different from other data type?

Dear all,

I compiled c program with llvm and found something strange with
function pointer as following small example .

------------- In C Code --------------
float a (int value) {
    return value + 1;
};

typedef float (*funcptr_t) (int);

funcptr_t get_ptr(funcptr_t p) {
    return p;
}

float result = get_ptr(a)(4);

------------- In LLVM Code --------------

%4 = call float (i32)* (float (i32)*)* @get_ptr(float (i32)* @a1)
nounwind ; <float (i32)*> [#uses=1]
              ~~~~~~~~~~~~~~~~~~~~ VERY STRANGE RETURN TYPE !!!
%5 = call float %4(i32 4) nounwind ; <float> [#uses=1]

Why we need duplicated return type?

Best regards,

Hao Shen wrote:

Dear all,

I compiled c program with llvm and found something strange with
function pointer as following small example .

------------- In C Code --------------
float a (int value) {
     return value + 1;
};

typedef float (*funcptr_t) (int);

funcptr_t get_ptr(funcptr_t p) {
     return p;
}

float result = get_ptr(a)(4);

------------- In LLVM Code --------------

%4 = call float (i32)* (float (i32)*)* @get_ptr(float (i32)* @a1)
nounwind ;<float (i32)*> [#uses=1]
               ~~~~~~~~~~~~~~~~~~~~ VERY STRANGE RETURN TYPE !!!
%5 = call float %4(i32 4) nounwind ;<float> [#uses=1]

Why we need duplicated return type?

Maybe I've just been reading LLVM IR for too long, but this looks completely normal to me. :slight_smile:

To answer the question in the subject line, a function pointer is just yet another type, like a struct pointer or a char pointer, etc. The 'float (i32)' indicates a function that takes an i32 and returns a float, so 'float (i32)*' is the type of a pointer to that function. This is your funcptr_t. That makes 'float (i32)* (float (i32)*)*' the exact type you'd expect for get_ptr(); it takes a funcptr_t and it returns a funcptr_t. Note that the type is the type of @get_ptr itself, not the type that @get_ptr returns.

Why a duplicated return type? The part after the ; is a plain-text comment. By default LLVM prints <return type> [#uses=X] for every non-void instruction. Note that the <> aren't part of the type in this case.

Nick

Thanks a lot. I can understand the "float (i32)* (float (i32)*)*" is
the type of function instead of return value type.
But why in most LLVM call assembly, such as "%retval = call i32
@test(i32 %argc)" the "i32" is just the return value.

In the document, 'call' Instruction is defined as following:
  <result> = [tail] call [cconv] [ret attrs] <ty> [<fnty>*]
<fnptrval>(<function args>) [fn attrs]

'ty': the type of the call instruction itself which is also the type
of the return value. Functions that return no value are marked void.

Would you please explain this?

Hao

Hi Hao Shen,

%4 = call float (i32)* (float (i32)*)* @get_ptr(float (i32)* @a1)
nounwind ;<float (i32)*> [#uses=1]
               ~~~~~~~~~~~~~~~~~~~~ VERY STRANGE RETURN TYPE !!!

this is a comment, and only exists to help the human reader. Comments
start with a semi-colon (;). You can remove them if you like.

Ciao,

Duncan.

I'm sorry that I should remove the comment.

In fact my question is about the "float (i32)* (float (i32)*)*", why
we use this kind of return type instead of just "float (i32)*".

Thanks a lot.
Hao

“float (i32)* (float (i32))” is not a return type.
According to the description of the ‘call’ instruction in LLVM Assembly Language Reference Manual (http://llvm.org/docs/LangRef.html#i_call) this is a signature of the pointer to function value being invoked (which includes the return type). In your case the full signature is printed because get_ptr returns a pointer to function (read item 5 in the Arguments section of the ‘call’ Instruction section).

Victor

These two are equivalent in the .ll file syntax:
  call void @foo()
and:
  call void()* @foo()

The .ll printer uses the first when it can because it is cleaner and easier to read. It can't do this for varargs and for functions returning a pointer to a function (because of ambiguity issues).

-Chris

OK. I understand. Thanks a lot for all of you.

Best regards,
Hao