Dear All,
In the LLVM IR, both formal parameters in functions and actual parameters in call instruction can have a set of attributes. However, it seems that there is no consistency check between attributes of formal parameters and attributes for actual ones. For example, consider the following llvm code:
%struct.example = type { i64, i64, i64, i64, double }
define void @should_be_pass_by_value(%struct.example* byval align 8 %para) {
……
}
define void @do_something() {
entry:
%foo = alloca %struct.example, align 8
call void @should_be_pass_by_value(%struct.example* %foo)
ret void
}
The code demonstrate the situation where the caller omit the ‘byval’ attribute of the parameter when calling the function. In this case, the llvm compiler could actually break the code if no inline, since the caller and callee disagree on the binary prototype of the function. For instance, in x86_64 SYS V ABI, complex structs (larger than four eightbytes) passed by value are directly constructed on stack by caller and accessed by callee. If not passed by value (pass by pointer), a pointer to the struct shall be passed as an integer to the callee. As a result, the caller will be end up using the wrong prototype of the function.
To make things worse, consider the following llvm code compiled from C targeting x86_64:
%struct.example = type { i64, i64, i64, i64, double }
@external_func_pass_by_value = external global void (%struct.example*)*
define void @do_something() {
entry:
%foo = alloca %struct.example, align 8
%func_to_call = load void (%struct.example*)** @external_func_pass_by_value, align 8
call void %func_to_call(%struct.example* byval align 8 %foo)
ret void
}
The corresponding C source is something like:
typedef struct {
long long a;
long long b;
long long c;
long long d;
double e;
}example;
typedef void (*pF_t)(example);
extern pF_t external_func_pass_by_value;
void do_something(void)
{
example foo;
(*external_func_pass_by_value)(foo);
}
In this case, the calling function is defined externally as a function pointer. The type of the function pointer will not expose the attributes of the parameters in the function to the current ‘Module’. There might be no effective ways to check whether the struct ‘example’ should be passed by value or not when an indirect call to the function is made. Currently the implementation of ‘FunctionType’ does not embed ‘byval’ attribute in itself. Consequently it could be troublesome that functions share the same ‘FunctionType’ differ in both C prototype and binary prototype only because of the difference in parameter attribute.
Should we put the important parameter attributes which can alter the function prototype directly into ‘FunctionType’? The subproject we are working on preforms some transformation of llvm ‘Modules’. During the transformation, both direct and indirect function calls (‘CallInst’) gets inserted. It would be much more convenient that the “important” parameter attributes can be deduced from ‘FunctionType’.
Sincerely,
Bo