arrow_back_ios Back to List

Implicit Function Duplication

Offload KB - features

Old Content Alert

Please note that this is a old document archive and the will most likely be out-dated or superseded by various other products and is purely here for historical purposes.

The essential and integral feature of Codeplay Offload to offload code to other processor cores (SPUs) is implicit function duplication. Whereas code outside an offload block is compiled for the PPU, the code inside offload blocks is compiled separately for the SPU. This means that calls inside offload blocks to normal PPU functions are compiled by automatically duplicating the called functions (including the entire call graph) to be offload functions for SPU. In the source code below, for example, the offload block calls a function with different combinations of outer and local references as parameters and the compiler will automatically generate a duplicate for each used combination.

int func(int & a, int & b)
{
	return a * b;
}

int main()
{
	int a = 2;
	int result = func(a, a); // PPU func(int&,int&);
	__blockingoffload()
	{
		int b = 3;
		b = func(a, b); // duplicated func(__outer int &, int &)
		b = func(b, a); // duplicated func(int & ,__outer int &)
		result += func(b, b); // duplicated func(int &, int &)
	};
}

Function duplication is performed by recompiling the source of the function (after preprocessing has been performed) using the new pointer and reference types and adding the offload attribute to the function definition. For example, when calling;

b = func(a, b); // duplicated func(__outer int &, int &)

the compiler internally generates and calls the following function;

__offload int func(__outer int & a, int & b)
{
	return a * b;
}

Duplicating functions that return pointer types

If a function to be duplicated returns a pointer/reference type the compiler will attempt to determine the outer property of the return pointer type if that function has already been defined. If that function has not been defined yet the compiler will assume a local pointer type for the return value.

Function duplication has an impact on overload resolution.

int * func(void *);
__offload float * func(int *);

int * optr;
int main()
{
	int * ivar = func(optr); // calls int * func(__outer void *)
	__blockingoffload()
	{
		int * ptr;
		void * vptr;
		float * fl = func(ptr);  // calls offload float * func(int *)
		int * ivar = func(optr); // calls duplicated int * func(__outer void *)
		int * fl = func(vptr); // calls duplicated int * func(void *)
	};
}

Without function duplication, only the second function would be viable for calls from inside a offload scope. With function duplication, the first (non-offload) function or more specifically its duplicates (because they would be compiled for SPU) become viable, too. The compiler then applies normal overload resolution (extended match outer pointers) to select the appropriate function.

Another blog on call-graph duplication can be found here