Wiki Roadmap Timeline Tickets New Ticket Source Search Help / Guide About Trac Login

Ticket #382 (new defect)

Opened 2 years ago

Last modified 2 years ago

extern C functions do not pass/receive structs correctly on X86_64

Reported by: SiegeLord Assigned to: ChristianK
Priority: major Milestone:
Component: unspecified Version: hg tip
Keywords: Cc:

Description

Given two functions, function A which returns a struct and function B which accepts a struct, writing B(A()) corrupts the passed struct if both A and B have the C calling convention on 64 bit systems. This works fine on 32 bit LDC and with DMD 1.053.

Sample code to reproduce the bug:

import tango.io.Stdout;

extern (C)
{
	struct Color
	{
		float r,g,b,a;
	}

	Color C_GetColor(float r, float g, float b, float a)
	{
		return Color(r,g,b,a);
	}

	void C_PrintColor(Color color)
	{
		Stdout.formatln("{} {} {} {}", color.r, color.g, color.b, color.a);
	}
}

Color GetColor(float r, float g, float b, float a)
{
	return Color(r,g,b,a);
}

void PrintColor(Color color)
{
	Stdout.formatln("{} {} {} {}", color.r, color.g, color.b, color.a);
}

void main()
{
	//Prints # # 1.00 2.00
	//where # is some random number
	C_PrintColor(C_GetColor(1, 2, 3, 4));
	
	Color color = C_GetColor(1, 2, 3, 4);
	//Prints 1.00 2.00 3.00 4.00
	C_PrintColor(color);
	
	//Prints 1.00 2.00 3.00 4.00
	PrintColor(GetColor(1, 2, 3, 4));
	
	//Prints 1.00 2.00 3.00 4.00
	PrintColor(C_GetColor(1, 2, 3, 4));
	
	//Prints 1.00 2.00 3.00 4.00
	C_PrintColor(GetColor(1, 2, 3, 4));
}

Change History

12/27/09 13:51:42 changed by darkjames

_Dmain from --output-ll:

  %0 = alloca %10                                 ; <%10*> [#uses=2]
  %1 = alloca %testcase.Color                     ; <%testcase.Color*> [#uses=2]
  %2 = alloca %testcase.Color*                    ; <%testcase.Color**> [#uses=2]
  [... more variables ...]
  %tmp = call %9 @C_GetColor(float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00) ; <%9> [#uses=1]
  store %9 %tmp, %9* %0
  %tmp1 = bitcast %9* %0 to %testcase.Color*      ; <%testcase.Color*> [#uses=1]
  %get-result = load %testcase.Color* %tmp1       ; <%testcase.Color> [#uses=1]
  store %testcase.Color %get-result, %testcase.Color* %1
  store %testcase.Color* %1, %testcase.Color** %2
  %tmp2 = bitcast %testcase.Color** %2 to %9*     ; <%9*> [#uses=1]
  %put-result = load %9* %tmp2                    ; <%9> [#uses=1]
  call void @C_PrintColor(%9 %put-result)
  [... more code ...]

I'm not familliar with x86-64 ABI, (neither of LLVM instructions) :)

But I don't understand this part:

  store %testcase.Color* %1, %testcase.Color** %2
  %tmp2 = bitcast %testcase.Color** %2 to %9*     ; <%9*> [#uses=1]

If i change it just to:

  %tmp2 = bitcast %testcase.Color* %1 to %9*      ; <%9*> [#uses=1]

After compilation (llvm-as,llc,gcc) it generates correct result.

Copyright © 2008, LDC Development Team.