[LLVMdev] Parameter Attributes in Call instruction and Function

ganboing ganboing at gmail.com
Tue Apr 22 00:56:36 PDT 2014


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







More information about the llvm-dev mailing list