From 59f9b35ceab115e2199ad0cc78dec1c2c2c8092d Mon Sep 17 00:00:00 2001 From: Frits van Bommel Date: Fri, 22 May 2009 13:17:06 +0200 Subject: [PATCH] Count the sret register as well when keeping track of how many integer registers are available for extern(C) functions on x86-64. Interestingly, llvm-g++ seems to have a very similar bug: http://llvm.org/pr4242 (So this breaks ABI-compatibility with llvm-gcc for this corner case, but gains it with gcc...) To clarify, this is about code like this: {{{ struct S { void*[3] data; } struct T { void*[2] data; } // The T should be passed in memory, and p in the last int register. extern(C) S fail(int, int, int, int, T t, void* p) { S s; s.data[0] = t.data[0]; s.data[1] = t.data[1]; s.data[2] = p; return s; } }}} which should generate code functionally equivalent to this: {{{ extern(C) S* succeed(S* s, int, int, int, int, T t, void* p) { s.data[0] = t.data[0]; s.data[1] = t.data[1]; s.data[2] = p; return s; } }}} (with the same definitions for S and T) --- gen/abi-x86-64.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gen/abi-x86-64.cpp b/gen/abi-x86-64.cpp index ac3ab57f..6d7fb285 100644 --- a/gen/abi-x86-64.cpp +++ b/gen/abi-x86-64.cpp @@ -562,7 +562,14 @@ bool X86_64TargetABI::returnInArg(TypeFunction* tf) { return false; Classification cl = classify(rt); - return cl.isMemory; + if (cl.isMemory) { + assert(state().int_regs > 0 + && "No int registers available when determining sret-ness?"); + // An sret parameter takes an integer register. + state().int_regs--; + return true; + } + return false; } }