diff mbox

[1/2,libgo] Add reflection support to gccgo for ppc64, ppc64le in gcc 4.9

Message ID 54AC0154.7020700@linux.vnet.ibm.com
State New
Headers show

Commit Message

Lynn A. Boger Jan. 6, 2015, 3:37 p.m. UTC
Add support for reflection for gccgo in gcc 4.9.  This is not a backport 
because reflection support in gcc trunk is done using FFI. Bootstrap 
built and tested on ppc64, ppc64le.

2015-01-06    Lynn Boger <laboger@linux.vnet.ibm.com>

     * libgo/Makefile.am:  Build the new files for libgo reflection 
support on ppc64, ppc64le
     * libgo/Makefile.in:  same
     * libgo/go/reflect/makefunc.go:  Invoke reflection functions for 
ppc64, ppc64le
     * libgo/go/reflect/makefunc_ppc.c:  makeFuncStub for ppc64, ppc64le
     * libgo/go/reflect/makefuncgo_ppc.go:  MakeFuncStubGo and argument 
handling for ppc64, ppc64le

Comments

Lynn A. Boger Jan. 6, 2015, 6:38 p.m. UTC | #1
Sorry, hold off on this one for now.  I missed the update to 
libgo/go/reflect/all_test.go for ppc64 and ppc64le in this patch and 
when changed to actually test these goarch values it is failing.

On 01/06/2015 09:37 AM, Lynn A. Boger wrote:
> Add support for reflection for gccgo in gcc 4.9.  This is not a 
> backport because reflection support in gcc trunk is done using FFI. 
> Bootstrap built and tested on ppc64, ppc64le.
>
> 2015-01-06    Lynn Boger <laboger@linux.vnet.ibm.com>
>
>     * libgo/Makefile.am:  Build the new files for libgo reflection 
> support on ppc64, ppc64le
>     * libgo/Makefile.in:  same
>     * libgo/go/reflect/makefunc.go:  Invoke reflection functions for 
> ppc64, ppc64le
>     * libgo/go/reflect/makefunc_ppc.c:  makeFuncStub for ppc64, ppc64le
>     * libgo/go/reflect/makefuncgo_ppc.go:  MakeFuncStubGo and argument 
> handling for ppc64, ppc64le
>
>
Lynn A. Boger Jan. 7, 2015, 4:02 p.m. UTC | #2
Would it be possible to add this patch to the gcc 4.9 branch as is? It 
provides most of the basic support for reflection on ppc64 and ppc64le, 
which does not work at all currently.  Once I get the 
libgo/go/reflect/all_test.go working I can add the patch for the fixes 
and enable the testcase for these goarch values in a later submission.

Thanks.

On 01/06/2015 12:38 PM, Lynn A. Boger wrote:
> Sorry, hold off on this one for now.  I missed the update to 
> libgo/go/reflect/all_test.go for ppc64 and ppc64le in this patch and 
> when changed to actually test these goarch values it is failing.
>
> On 01/06/2015 09:37 AM, Lynn A. Boger wrote:
>> Add support for reflection for gccgo in gcc 4.9.  This is not a 
>> backport because reflection support in gcc trunk is done using FFI. 
>> Bootstrap built and tested on ppc64, ppc64le.
>>
>> 2015-01-06    Lynn Boger <laboger@linux.vnet.ibm.com>
>>
>>     * libgo/Makefile.am:  Build the new files for libgo reflection 
>> support on ppc64, ppc64le
>>     * libgo/Makefile.in:  same
>>     * libgo/go/reflect/makefunc.go:  Invoke reflection functions for 
>> ppc64, ppc64le
>>     * libgo/go/reflect/makefunc_ppc.c:  makeFuncStub for ppc64, ppc64le
>>     * libgo/go/reflect/makefuncgo_ppc.go:  MakeFuncStubGo and 
>> argument handling for ppc64, ppc64le
>>
>>
>
>
>
Ian Lance Taylor Jan. 7, 2015, 4:06 p.m. UTC | #3
On Tue, Jan 6, 2015 at 7:37 AM, Lynn A. Boger
<laboger@linux.vnet.ibm.com> wrote:
> Add support for reflection for gccgo in gcc 4.9.  This is not a backport
> because reflection support in gcc trunk is done using FFI. Bootstrap built
> and tested on ppc64, ppc64le.

Sorry, I didn't see at first that this is not a backport.  This is a
complex patch that has never been tested on trunk.  We don't this kind
of change on release branches.  For this kind of work you'll need to
maintain your own branch.  Sorry.

Ian
Lynn A. Boger Jan. 7, 2015, 4:43 p.m. UTC | #4
I thought that since this only affects ppc64 and ppc64le, and provides 
reflection support that doesnt exist in gcc 4.9 for Power (you get a 
panic if you try to use reflection on ppc64, ppc64le), it would be OK.

We'll look at putting it in our own branch.

On 01/07/2015 10:06 AM, Ian Lance Taylor wrote:
> On Tue, Jan 6, 2015 at 7:37 AM, Lynn A. Boger
> <laboger@linux.vnet.ibm.com> wrote:
>> Add support for reflection for gccgo in gcc 4.9.  This is not a backport
>> because reflection support in gcc trunk is done using FFI. Bootstrap built
>> and tested on ppc64, ppc64le.
> Sorry, I didn't see at first that this is not a backport.  This is a
> complex patch that has never been tested on trunk.  We don't this kind
> of change on release branches.  For this kind of work you'll need to
> maintain your own branch.  Sorry.
>
> Ian
>
>
>
Ian Lance Taylor Jan. 7, 2015, 4:54 p.m. UTC | #5
On Wed, Jan 7, 2015 at 8:43 AM, Lynn A. Boger
<laboger@linux.vnet.ibm.com> wrote:
>
> I thought that since this only affects ppc64 and ppc64le, and provides
> reflection support that doesnt exist in gcc 4.9 for Power (you get a panic
> if you try to use reflection on ppc64, ppc64le), it would be OK.

I understand that the code doesn't work today in 4.9, but a release
branch is for releases and backports of bug fixes, not for any sort of
new development.

(As far as I knoew reflection works in general for PPC in 4.9, it's
just reflect.MakeFunc, a rarely used feature, that is broken.)

Ian
Lynn A. Boger Jan. 7, 2015, 5:26 p.m. UTC | #6
In libgo/go/reflect/makefunc.go, calls to MakeFunc, makeMethodValue and 
makeValueMethod will panic if called when GOARCH is ppc64 or ppc64le.

I understand your point about what you allow into a release branch and 
since it has known bugs with an existing testcase then I agree it 
shouldn't be accepted the way it is.  I will work on fixing that and 
then figure out what branch is best to include it in.

On 01/07/2015 10:54 AM, Ian Lance Taylor wrote:
> On Wed, Jan 7, 2015 at 8:43 AM, Lynn A. Boger
> <laboger@linux.vnet.ibm.com> wrote:
>> I thought that since this only affects ppc64 and ppc64le, and provides
>> reflection support that doesnt exist in gcc 4.9 for Power (you get a panic
>> if you try to use reflection on ppc64, ppc64le), it would be OK.
> I understand that the code doesn't work today in 4.9, but a release
> branch is for releases and backports of bug fixes, not for any sort of
> new development.
>
> (As far as I knoew reflection works in general for PPC in 4.9, it's
> just reflect.MakeFunc, a rarely used feature, that is broken.)
>
> Ian
>
>
>
Ian Lance Taylor Jan. 7, 2015, 6:52 p.m. UTC | #7
On Wed, Jan 7, 2015 at 9:26 AM, Lynn A. Boger
<laboger@linux.vnet.ibm.com> wrote:
>
> In libgo/go/reflect/makefunc.go, calls to MakeFunc, makeMethodValue and
> makeValueMethod will panic if called when GOARCH is ppc64 or ppc64le.

Right, I'm just saying that almost no code actually does that.  I just
tried a web search and found no uses other than examples of how to use
it.  I'm sure there are a few, but not many.

Ian
Michael Hudson-Doyle Jan. 8, 2015, 12:39 a.m. UTC | #8
Ian Lance Taylor <iant@golang.org> writes:

> On Wed, Jan 7, 2015 at 9:26 AM, Lynn A. Boger
> <laboger@linux.vnet.ibm.com> wrote:
>>
>> In libgo/go/reflect/makefunc.go, calls to MakeFunc, makeMethodValue and
>> makeValueMethod will panic if called when GOARCH is ppc64 or ppc64le.
>
> Right, I'm just saying that almost no code actually does that.  I just
> tried a web search and found no uses other than examples of how to use
> it.  I'm sure there are a few, but not many.

There is a somewhat hidden one in Docker:

    https://github.com/docker/docker/blob/master/api/client/cli.go#L64

(it is also possible to patch docker to do this differently, of course).

Cheers,
mwh
Ian Lance Taylor Jan. 8, 2015, 1:20 a.m. UTC | #9
On Wed, Jan 7, 2015 at 4:39 PM, Michael Hudson-Doyle
<michael.hudson@canonical.com> wrote:
> Ian Lance Taylor <iant@golang.org> writes:
>
>> On Wed, Jan 7, 2015 at 9:26 AM, Lynn A. Boger
>> <laboger@linux.vnet.ibm.com> wrote:
>>>
>>> In libgo/go/reflect/makefunc.go, calls to MakeFunc, makeMethodValue and
>>> makeValueMethod will panic if called when GOARCH is ppc64 or ppc64le.
>>
>> Right, I'm just saying that almost no code actually does that.  I just
>> tried a web search and found no uses other than examples of how to use
>> it.  I'm sure there are a few, but not many.
>
> There is a somewhat hidden one in Docker:
>
>     https://github.com/docker/docker/blob/master/api/client/cli.go#L64
>
> (it is also possible to patch docker to do this differently, of course).

Ah, so that is why it matters.

Perhaps you could talk Docker into replace the return statement with

return func(a ...string) error {
	return method.CallSlice([]reflect.Value{reflect.ValueOf(a)})[0].Interface().(error)
}, true

It would probably be just as efficient.

Ian
Lynn A. Boger Jan. 8, 2015, 1:44 p.m. UTC | #10
If this change is not included, in the gcc go testsuite, the recover.go 
testcase fails with this error:

panic: reflect.makeMethodValue not implemented for ppc64le

when running this test:

func test9reflect1() {
         f := reflect.ValueOf(&T1{}).Method(0).Interface().(func())
         defer f()
         panic(9)
}

Also as was noted below, some level of reflection support is needed to 
build Docker.  I was given this patch by someone in IBM trying to build 
Docker on Power who told me it was needed (but didn't really know the 
details).  There is interest in trying to get Docker to build with gcc 
4.9 because 5.0 won't be available in distros for a while yet.  I was 
told that the minimal reflection support provided by this patch was 
enough to get it to build.  But if a simple workaround in the Docker 
source will make it work that might be sufficient.  I'll find out.  Thanks.

On 01/07/2015 07:20 PM, Ian Lance Taylor wrote:
> On Wed, Jan 7, 2015 at 4:39 PM, Michael Hudson-Doyle
> <michael.hudson@canonical.com> wrote:
>> Ian Lance Taylor <iant@golang.org> writes:
>>
>>> On Wed, Jan 7, 2015 at 9:26 AM, Lynn A. Boger
>>> <laboger@linux.vnet.ibm.com> wrote:
>>>> In libgo/go/reflect/makefunc.go, calls to MakeFunc, makeMethodValue and
>>>> makeValueMethod will panic if called when GOARCH is ppc64 or ppc64le.
>>> Right, I'm just saying that almost no code actually does that.  I just
>>> tried a web search and found no uses other than examples of how to use
>>> it.  I'm sure there are a few, but not many.
>> There is a somewhat hidden one in Docker:
>>
>>      https://github.com/docker/docker/blob/master/api/client/cli.go#L64
>>
>> (it is also possible to patch docker to do this differently, of course).
> Ah, so that is why it matters.
>
> Perhaps you could talk Docker into replace the return statement with
>
> return func(a ...string) error {
> 	return method.CallSlice([]reflect.Value{reflect.ValueOf(a)})[0].Interface().(error)
> }, true
>
> It would probably be just as efficient.
>
> Ian
>
>
Ian Lance Taylor Jan. 8, 2015, 2:53 p.m. UTC | #11
On Thu, Jan 8, 2015 at 5:44 AM, Lynn A. Boger
<laboger@linux.vnet.ibm.com> wrote:
>
> Also as was noted below, some level of reflection support is needed to build
> Docker.

Sorry to be so pedantic, but I'm just trying to clarify that you keep
saying "reflection support," but reflection support is there.  What is
missing is a miniscule rarely used part of the reflect package, namely
support for reflect.MakeFunc, and, it's true, calling reflect.ValueOf,
then Method or MethodByName, then Interface.

Ian
Lynn A. Boger Jan. 8, 2015, 4:22 p.m. UTC | #12
The only bugs I am aware of when using reflection on ppc64 & ppc64le in 
gcc 4.9 are in the gccgo testcase recover.go and what is needed to build 
Docker.  When I run the gccgo testsuite and see a failing testcase with 
a panic message saying that a function is not implemented it makes me 
think some major pieces are missing so that is why I've used that 
phrase.  Also I noticed that the libgo/go/reflect/all_test.go testcase 
is not running some tests when GOARCH is ppc64 or ppc64le, and if those 
are enabled they fail.  So some might call those "bugs" or 
"unimplemented features" or "missing support".  To me, a message saying 
that something is not implemented is considered missing support even 
though it might be minor.

The information I received from those who had attempted to build Docker 
on ppc64le in gcc 4.9 said that it needed reflection and it wasn't there 
and this patch was used to make it work.

I hope that answers your question?  I have not done a thorough 
testing/investigation of reflection in gccgo 4.9 on Power and my 
statement refers only on the above information.

On 01/08/2015 08:53 AM, Ian Lance Taylor wrote:
> On Thu, Jan 8, 2015 at 5:44 AM, Lynn A. Boger
> <laboger@linux.vnet.ibm.com> wrote:I
>> Also as was noted below, some level of reflection support is needed to build
>> Docker.
> Sorry to be so pedantic, but I'm just trying to clarify that you keep
> saying "reflection support," but reflection support is there.  What is
> missing is a miniscule rarely used part of the reflect package, namely
> support for reflect.MakeFunc, and, it's true, calling reflect.ValueOf,
> then Method or MethodByName, then Interface.
>
> Ian
>
>
>
Lynn A. Boger Jan. 14, 2015, 1:49 p.m. UTC | #13
I have an updated patch for the reflection functions in gcc 4.9 for 
ppc64 & ppc64le which allows the recover.go test to pass and the updated 
version of libgo/go/reflect/all_tests.go to pass once all testcases are 
enabled for ppc64 & ppc64le.

Based on the discussion we've had on this patch, has the decision 
changed concerning whether or not this patch might be accepted into the 
gcc 4.9 branch?  If so, I will post the updated patch.

On 01/08/2015 08:53 AM, Ian Lance Taylor wrote:
> On Thu, Jan 8, 2015 at 5:44 AM, Lynn A. Boger
> <laboger@linux.vnet.ibm.com> wrote:
>> Also as was noted below, some level of reflection support is needed to build
>> Docker.
> Sorry to be so pedantic, but I'm just trying to clarify that you keep
> saying "reflection support," but reflection support is there.  What is
> missing is a miniscule rarely used part of the reflect package, namely
> support for reflect.MakeFunc, and, it's true, calling reflect.ValueOf,
> then Method or MethodByName, then Interface.
>
> Ian
>
>
>
Ian Lance Taylor Jan. 14, 2015, 3:24 p.m. UTC | #14
On Wed, Jan 14, 2015 at 5:49 AM, Lynn A. Boger
<laboger@linux.vnet.ibm.com> wrote:
> I have an updated patch for the reflection functions in gcc 4.9 for ppc64 &
> ppc64le which allows the recover.go test to pass and the updated version of
> libgo/go/reflect/all_tests.go to pass once all testcases are enabled for
> ppc64 & ppc64le.
>
> Based on the discussion we've had on this patch, has the decision changed
> concerning whether or not this patch might be accepted into the gcc 4.9
> branch?  If so, I will post the updated patch.

To me it is not appropriate to add brand new code, code that has never
been in mainline, to an existing release branch.  That is not what
release branches are for.  Release branches are for backports of bug
fixes, not for new code.

I assume that the people who want this code are not going to sit on
their hands waiting for the 4.9.3 release, which won't happen for
several months even in the best case.  Why not provide this code as a
separate patch on top of the 4.9 releases?  Or manage your own branch
if necessary?

Ian
Lynn A. Boger Jan. 14, 2015, 3:40 p.m. UTC | #15
Yes, I have other options, I just wanted to verify that this was still 
your answer.

Thanks.

On 01/14/2015 09:24 AM, Ian Lance Taylor wrote:
> On Wed, Jan 14, 2015 at 5:49 AM, Lynn A. Boger
> <laboger@linux.vnet.ibm.com> wrote:
>> I have an updated patch for the reflection functions in gcc 4.9 for ppc64 &
>> ppc64le which allows the recover.go test to pass and the updated version of
>> libgo/go/reflect/all_tests.go to pass once all testcases are enabled for
>> ppc64 & ppc64le.
>>
>> Based on the discussion we've had on this patch, has the decision changed
>> concerning whether or not this patch might be accepted into the gcc 4.9
>> branch?  If so, I will post the updated patch.
> To me it is not appropriate to add brand new code, code that has never
> been in mainline, to an existing release branch.  That is not what
> release branches are for.  Release branches are for backports of bug
> fixes, not for new code.
>
> I assume that the people who want this code are not going to sit on
> their hands waiting for the 4.9.3 release, which won't happen for
> several months even in the best case.  Why not provide this code as a
> separate patch on top of the 4.9 releases?  Or manage your own branch
> if necessary?
>
> Ian
>
>
>
Ian Lance Taylor Feb. 6, 2015, 11:05 p.m. UTC | #16
On Fri, Feb 6, 2015 at 12:36 PM, Lynn A. Boger
<laboger@linux.vnet.ibm.com> wrote:
>
> I was told by the testers that this patch did not work.  The error message
> was:
>
>> panic: interface conversion: interface is nil, not error
>>
>> goroutine 1 [running]:
>> client.$nested1
>>     /home/ubuntu/docker.mainline/src/github.com/docker/docker/api/
>> client/cli.go:66
>>
>> github_com_docker_docker_api_client.Cmd.pN45_github_com_docker_docker_api_client.DockerCli
>>     /home/ubuntu/docker.mainline/src/github.com/docker/docker/api/
>> client/cli.go:84
>> main.main
>>     /home/ubuntu/docker/docker/docker.go:126


That's easy to fix....

Ian
Lynn A. Boger Feb. 12, 2015, 8:30 p.m. UTC | #17
Not sure I would call it "easy" but I was able to reproduce the problem 
and then get it to work with this, at least in my testcase:

   f := func(a ...string) error {
                         switch t := 
mv.CallSlice([]reflect.Value{reflect.ValueOf(a)})[0].Interface().(type) {
                         case error:
                                 return t
                         default:
                                 return nil
                         }
                 }

On 02/06/2015 05:05 PM, Ian Lance Taylor wrote:
> On Fri, Feb 6, 2015 at 12:36 PM, Lynn A. Boger
> <laboger@linux.vnet.ibm.com> wrote:
>> I was told by the testers that this patch did not work.  The error message
>> was:
>>
>>> panic: interface conversion: interface is nil, not error
>>>
>>> goroutine 1 [running]:
>>> client.$nested1
>>>      /home/ubuntu/docker.mainline/src/github.com/docker/docker/api/
>>> client/cli.go:66
>>>
>>> github_com_docker_docker_api_client.Cmd.pN45_github_com_docker_docker_api_client.DockerCli
>>>      /home/ubuntu/docker.mainline/src/github.com/docker/docker/api/
>>> client/cli.go:84
>>> main.main
>>>      /home/ubuntu/docker/docker/docker.go:126
>
> That's easy to fix....
>
> Ian
>
>
diff mbox

Patch

Index: libgo/Makefile.am
===================================================================
--- libgo/Makefile.am	(revision 219198)
+++ libgo/Makefile.am	(working copy)
@@ -925,11 +925,25 @@  go_reflect_makefunc_file = \
 go_reflect_makefunc_s_file = \
 	go/reflect/makefunc_386.S
 else
+if LIBGO_IS_PPC64
+go_reflect_makefunc_file = \
+	go/reflect/makefuncgo_ppc.go
+go_reflect_makefunc_s_file = \
+	go/reflect/makefunc_ppc.c
+else
+if LIBGO_IS_PPC64LE
+go_reflect_makefunc_file = \
+	go/reflect/makefuncgo_ppc.go
+go_reflect_makefunc_s_file = \
+	go/reflect/makefunc_ppc.c
+else
 go_reflect_makefunc_file =
 go_reflect_makefunc_s_file = \
 	go/reflect/makefunc_dummy.c
 endif
 endif
+endif
+endif
 
 go_reflect_files = \
 	go/reflect/deepequal.go \
Index: libgo/Makefile.in
===================================================================
--- libgo/Makefile.in	(revision 219198)
+++ libgo/Makefile.in	(working copy)
@@ -1097,7 +1097,13 @@  go_path_files = \
 	go/path/match.go \
 	go/path/path.go
 
-@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = 
+@LIBGO_IS_386_FALSE@@LIBGO_IS_PPC64LE_FALSE@@LIBGO_IS_PPC64_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = 
+@LIBGO_IS_386_FALSE@@LIBGO_IS_PPC64LE_TRUE@@LIBGO_IS_PPC64_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \
+@LIBGO_IS_386_FALSE@@LIBGO_IS_PPC64LE_TRUE@@LIBGO_IS_PPC64_FALSE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefuncgo_ppc.go
+
+@LIBGO_IS_386_FALSE@@LIBGO_IS_PPC64_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \
+@LIBGO_IS_386_FALSE@@LIBGO_IS_PPC64_TRUE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefuncgo_ppc.go
+
 @LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_file = \
 @LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefuncgo_386.go
 
@@ -1104,9 +1110,15 @@  go_path_files = \
 @LIBGO_IS_X86_64_TRUE@go_reflect_makefunc_file = \
 @LIBGO_IS_X86_64_TRUE@	go/reflect/makefuncgo_amd64.go
 
-@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
-@LIBGO_IS_386_FALSE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefunc_dummy.c
+@LIBGO_IS_386_FALSE@@LIBGO_IS_PPC64LE_FALSE@@LIBGO_IS_PPC64_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
+@LIBGO_IS_386_FALSE@@LIBGO_IS_PPC64LE_FALSE@@LIBGO_IS_PPC64_FALSE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefunc_dummy.c
 
+@LIBGO_IS_386_FALSE@@LIBGO_IS_PPC64LE_TRUE@@LIBGO_IS_PPC64_FALSE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
+@LIBGO_IS_386_FALSE@@LIBGO_IS_PPC64LE_TRUE@@LIBGO_IS_PPC64_FALSE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefunc_ppc.c
+
+@LIBGO_IS_386_FALSE@@LIBGO_IS_PPC64_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
+@LIBGO_IS_386_FALSE@@LIBGO_IS_PPC64_TRUE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefunc_ppc.c
+
 @LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@go_reflect_makefunc_s_file = \
 @LIBGO_IS_386_TRUE@@LIBGO_IS_X86_64_FALSE@	go/reflect/makefunc_386.S
 
Index: libgo/go/reflect/makefunc.go
===================================================================
--- libgo/go/reflect/makefunc.go	(revision 219198)
+++ libgo/go/reflect/makefunc.go	(working copy)
@@ -52,7 +52,7 @@  func MakeFunc(typ Type, fn func(args []Value) (res
 	}
 
 	switch runtime.GOARCH {
-	case "amd64", "386":
+	case "amd64", "386", "ppc64", "ppc64le":
 	default:
 		panic("reflect.MakeFunc not implemented for " + runtime.GOARCH)
 	}
@@ -91,7 +91,7 @@  func makeMethodValue(op string, v Value) Value {
 	}
 
 	switch runtime.GOARCH {
-	case "amd64", "386":
+	case "amd64", "386", "ppc64", "ppc64le":
 	default:
 		panic("reflect.makeMethodValue not implemented for " + runtime.GOARCH)
 	}
@@ -138,7 +138,7 @@  func makeValueMethod(v Value) Value {
 	}
 
 	switch runtime.GOARCH {
-	case "amd64", "386":
+	case "amd64", "386", "ppc64", "ppc64le":
 	default:
 		panic("reflect.makeValueMethod not implemented for " + runtime.GOARCH)
 	}
Index: libgo/go/reflect/makefunc_ppc.c
===================================================================
--- libgo/go/reflect/makefunc_ppc.c	(revision 0)
+++ libgo/go/reflect/makefunc_ppc.c	(working copy)
@@ -0,0 +1,102 @@ 
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "go-panic.h"
+
+extern void MakeFuncStubGo(void *, void *) asm ("reflect.MakeFuncStubGo");
+
+/* Structure to store all registers used for parameter passing.  */
+typedef struct
+{
+	long r3;
+	long r4;
+	long r5;
+	long r6;
+	long r7;
+	long r8;
+	long r9;
+	long r10;
+	/* Pointer to non-register arguments on the stack.  */
+	long stack_args;
+	double f1;
+	double f2;
+	double f3;
+	double f4;
+	double f5;
+	double f6;
+	double f7;
+	double f8;
+	double f9;
+	double f10;
+	double f11;
+	double f12;
+	double f13;
+} ppcRegs;
+
+void makeFuncStub(
+	long r3, long r4, long r5, long r6, long r7, long r8, long r9, long r10,
+	double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8,
+	double f9, double f10, double f11, double f12, double f13)
+	asm ("reflect.makeFuncStub");
+
+void makeFuncStub(
+	long r3, long r4, long r5, long r6, long r7, long r8, long r9, long r10,
+	double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8,
+	double f9, double f10, double f11, double f12, double f13)
+{
+	ppcRegs regs;
+	long tmpreg;
+	void *closure;
+
+	/* Store the registers in a structure that is passed on to the Go stub
+	   function.  */
+	regs.r3 = r3;
+	regs.r4 = r4;
+	regs.r5 = r5;
+	regs.r6 = r6;
+	regs.r7 = r7;
+	regs.r8 = r8;
+	regs.r9 = r9;
+	regs.r10 = r10;
+	regs.f1 = f1;
+	regs.f2 = f2;
+	regs.f3 = f3;
+	regs.f4 = f4;
+	regs.f5 = f5;
+	regs.f6 = f6;
+	regs.f7 = f7;
+	regs.f8 = f8;
+	regs.f9 = f9;
+	regs.f10 = f10;
+	regs.f11 = f11;
+	regs.f12 = f12;
+	regs.f13 = f13;
+
+
+	asm volatile(	"ld	%0,0(1)\n"	\
+			"addis	%0,%0,32\n"	\
+			"std	%0,0(%1)\n"	\
+			: "=r" (tmpreg)		\
+			: "a" (&regs.stack_args)\
+			: "memory");
+
+	/* For MakeFunc functions that call recover.  */
+	__go_makefunc_can_recover( __builtin_return_address (0));
+	/* Call the Go stub function.  */
+	closure = __go_get_closure();
+	MakeFuncStubGo(&regs, closure);
+	/* MakeFunc functions can no longer call recover.  */
+	__go_makefunc_returning();
+	/* Restore all possible return registers.  */
+
+	asm volatile ("ld\t3,0(%0)" : : "a" (&regs.r3) : "r3" );
+	asm volatile ("ld\t4,0(%0)" : : "a" (&regs.r4) : "r4" );
+	asm volatile ("lfd\t1,0(%0)" : : "a" (&regs.f1) : "fr1" );
+	asm volatile ("lfd\t2,0(%0)" : : "a" (&regs.f2) : "fr2" );
+	asm volatile ("lfd\t3,0(%0)" : : "a" (&regs.f3) : "fr3" );
+	asm volatile ("lfd\t4,0(%0)" : : "a" (&regs.f4) : "fr4" );
+
+	return;
+}
Index: libgo/go/reflect/makefuncgo_ppc.go
===================================================================
--- libgo/go/reflect/makefuncgo_ppc.go	(revision 0)
+++ libgo/go/reflect/makefuncgo_ppc.go	(working copy)
@@ -0,0 +1,620 @@ 
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// MakeFunc ppc implementation.
+
+package reflect
+
+import "unsafe"
+
+const ppc_arch_stack_slot_align uintptr = 8
+const ppc_num_gr = 8
+const ppc_num_fr = 13
+type ppc_arch_gr_t uint64
+type ppc_arch_fr_t uint64
+
+// The assembler stub will pass a pointer to this structure.
+// This will come in holding all the registers that might hold
+// function parameters.  On return we will set the registers that
+// might hold result values.
+type ppc_regs struct {
+	r3  ppc_arch_gr_t
+	r4  ppc_arch_gr_t
+	r5  ppc_arch_gr_t
+	r6  ppc_arch_gr_t
+	r7  ppc_arch_gr_t
+	r8  ppc_arch_gr_t
+	r9  ppc_arch_gr_t
+	r10 ppc_arch_gr_t
+	stack_args ppc_arch_gr_t
+	f1  ppc_arch_fr_t
+	f2  ppc_arch_fr_t
+	f3  ppc_arch_fr_t
+	f4  ppc_arch_fr_t
+	f5  ppc_arch_fr_t
+	f6  ppc_arch_fr_t
+	f7  ppc_arch_fr_t
+	f8  ppc_arch_fr_t
+	f9  ppc_arch_fr_t
+	f10 ppc_arch_fr_t
+	f11 ppc_arch_fr_t
+	f12 ppc_arch_fr_t
+	f13 ppc_arch_fr_t
+}
+
+// Argument classifications that arise for Go types.
+type ppc_arg_t int
+
+const (
+	ppc_general_reg ppc_arg_t = iota
+	ppc_float_reg
+	// Argument passed as a pointer to an in-memory value.
+	ppc_mem_ptr
+	ppc_slice
+	ppc_empty
+)
+
+// ppcClassifyParameter returns the register class needed to
+// pass the value of type TYP.  ppc_empty means the register is
+// not used.  The second and third return values are the offset of
+// an rtype parameter passed in a register (second) or stack slot
+// (third).
+func ppcClassifyParameter(typ *rtype) (ppc_arg_t, uintptr, uintptr) {
+	offset := ppc_arch_stack_slot_align - typ.Size()
+	if typ.Size() > ppc_arch_stack_slot_align {
+		offset = 0
+	}
+	switch typ.Kind() {
+	default:
+		panic("internal error--unknown kind in ppcClassifyParameter")
+	case Bool, Int, Int8, Int16, Int32, Uint, Uint8, Uint16, Uint32:
+		return ppc_general_reg, offset, offset
+	case Int64, Uint64, Uintptr, Chan, Func, Map, Ptr, UnsafePointer:
+		return ppc_general_reg, 0, 0
+	case Float32, Float64:
+		return ppc_float_reg, 0, offset
+	case Complex64, Complex128:
+		// Complex numbers are passed by reference.
+		return ppc_mem_ptr, 0, 0
+	case Array, Struct:
+		var ityp *rtype
+		var length int
+
+		if typ.Size() == 0 {
+			return ppc_empty, 0, 0
+		}
+		switch typ.Size() {
+		default:
+			// Pointer to memory.
+			return ppc_mem_ptr, 0, 0
+		case 1, 2:
+			// Pass in an integer register.
+			return ppc_general_reg, offset, offset
+
+		case 4, 8:
+			// See below.
+		}
+		if (typ.Kind() == Array) {
+			atyp := (*arrayType)(unsafe.Pointer(typ))
+			length = atyp.Len()
+			ityp = atyp.elem
+		} else {
+			styp := (*structType)(unsafe.Pointer(typ))
+			length = len(styp.fields)
+			ityp = styp.fields[0].typ
+		}
+		if length == 1 {
+			class, off_reg, off_slot := ppcClassifyParameter(ityp)
+			if class == ppc_float_reg {
+				// The array (stored in a structure) or struct
+				// is "equivalent to a floating point type" as
+				// defined in the S390x Abi.  Note that this
+				// can only be the case in the cases 4 and 8 of
+				// the switch above.
+				return ppc_float_reg, off_reg, off_slot
+			}
+		}
+		// Otherwise pass in an integer register.
+		switch typ.Size() {
+		case 4, 8:
+			return ppc_general_reg, offset, offset
+		default:
+			return ppc_general_reg, 0, 0
+		}
+	case Slice:
+		return ppc_slice, 0, 0
+	case Interface, String:
+		return ppc_mem_ptr, 0, 0
+	}
+}
+
+// ppcClassifyReturn returns the register classes needed to
+// return the value of type TYP.  s390_empty means the register is
+// not used.  The second value is the offset of an rtype return
+// parameter if stored in a register.
+func ppcClassifyReturn(typ *rtype) (ppc_arg_t, uintptr) {
+	offset := ppc_arch_stack_slot_align - typ.Size()
+	if typ.Size() > ppc_arch_stack_slot_align {
+		offset = 0;
+	}
+	switch typ.Kind() {
+	default:
+		panic("internal error--unknown kind in ppcClassifyReturn")
+	case Bool, Int, Int8, Int16, Int32, Int64,
+		Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
+
+		return ppc_general_reg, offset
+	case Chan, Func, Map, Ptr, UnsafePointer:
+		return ppc_general_reg, 0
+	case Interface:
+		return ppc_general_reg, 0		
+	case Float32, Float64:
+		return ppc_float_reg, 0
+	case Complex64, Complex128:
+		return ppc_mem_ptr, 0
+	case Slice, String:
+		return ppc_mem_ptr, 0
+	case Array, Struct:
+		if typ.size == 0 {
+			return ppc_empty, 0
+		}
+		// No optimization is done for returned structures and arrays.
+		return ppc_mem_ptr, 0
+	}
+}
+
+
+func ppcClassify(typ *rtype) (ppc_arg_t, ppc_arg_t) {
+	switch typ.Kind() {
+	default:
+		panic("internal error--unknown kind in amd64Classify")
+
+	case Bool, Int, Int8, Int16, Int32, Int64,
+		Uint, Uint8, Uint16, Uint32, Uint64,
+		Uintptr, Chan, Func, Map, Ptr, UnsafePointer:
+
+		return ppc_general_reg, ppc_empty
+
+	case Float32, Float64, Complex64:
+		return ppc_float_reg, ppc_empty
+
+	case Complex128:
+		return ppc_float_reg, ppc_float_reg
+
+	case Array:
+		if typ.size == 0 {
+			return ppc_empty, ppc_empty
+		} else if typ.size > 16 {
+			return ppc_mem_ptr, ppc_empty
+		}
+		atyp := (*arrayType)(unsafe.Pointer(typ))
+		eclass1, eclass2 := ppcClassify(atyp.elem)
+		if eclass1 == ppc_mem_ptr {
+			return ppc_mem_ptr, ppc_empty
+		}
+		if eclass2 == ppc_empty && typ.size > 8 {
+			eclass2 = eclass1
+		}
+		return eclass1, eclass2
+
+	case Interface:
+		return ppc_general_reg, ppc_general_reg
+
+	case Slice:
+		return ppc_mem_ptr, ppc_empty
+
+	case String:
+		return ppc_general_reg, ppc_general_reg
+
+	case Struct:
+		if typ.size == 0 {
+			return ppc_empty, ppc_empty
+		} else if typ.size > 16 {
+			return ppc_mem_ptr, ppc_empty
+		}
+		var first, second ppc_arg_t
+		f := ppc_empty
+		onFirst := true
+		styp := (*structType)(unsafe.Pointer(typ))
+		for _, field := range styp.fields {
+			if onFirst && field.offset >= 8 {
+				first = f
+				f = ppc_empty
+				onFirst = false
+			}
+			fclass1, fclass2 := ppcClassify(field.typ)
+			f = ppcMergeClasses(f, fclass1)
+			if fclass2 != ppc_empty {
+				if !onFirst {
+					panic("ppcClassify inconsistent")
+				}
+				first = f
+				f = fclass2
+				onFirst = false
+			}
+		}
+		if onFirst {
+			first = f
+			second = ppc_empty
+		} else {
+			second = f
+		}
+		if first == ppc_mem_ptr || second == ppc_mem_ptr {
+			return ppc_mem_ptr, ppc_empty
+		}
+		return first, second
+	}
+}
+
+
+// amd64MergeClasses merges two register classes as described in the
+// amd64 ELF ABI.
+func ppcMergeClasses(c1, c2 ppc_arg_t) ppc_arg_t {
+	switch {
+	case c1 == c2:
+		return c1
+	case c1 == ppc_empty:
+		return c2
+	case c2 == ppc_empty:
+		return c1
+	case c1 == ppc_mem_ptr || c2 == ppc_mem_ptr:
+		return ppc_mem_ptr
+	case c1 == ppc_general_reg || c2 == ppc_general_reg:
+		return ppc_general_reg
+	default:
+		return ppc_general_reg
+	}
+}
+
+
+
+// Given a value of type *rtype left aligned in an iword, reload
+// the value so that it can be stored in a general or floating
+// point register.  For general registers the value is sign extend
+// and right aligned.
+func ppcReloadForRegister(typ *rtype, w iword, offset uintptr) (iword) {
+	var do_sign_extend bool = false
+	var gr ppc_arch_gr_t
+
+	switch typ.Kind() {
+		case Int, Int8, Int16, Int32, Int64:
+			do_sign_extend = true
+		default:
+			// Handle all other cases in the next switch.
+	}
+	switch (typ.size) {
+		case 1:
+			if (do_sign_extend == true) {
+				se := int64(*(*int8)(unsafe.Pointer(&w)))
+				gr = *(*ppc_arch_gr_t)(unsafe.Pointer(&se))
+			} else {
+				e := int64(*(*uint8)(unsafe.Pointer(&w)))
+				gr = *(*ppc_arch_gr_t)(unsafe.Pointer(&e))
+			}
+		case 2:
+			if (do_sign_extend == true) {
+				se := int64(*(*int16)(unsafe.Pointer(&w)))
+				gr = *(*ppc_arch_gr_t)(unsafe.Pointer(&se))
+			} else {
+				e := int64(*(*uint16)(unsafe.Pointer(&w)))
+				gr = *(*ppc_arch_gr_t)(unsafe.Pointer(&e))
+			}
+		case 4:
+			if (do_sign_extend == true) {
+				se := int64(*(*int32)(unsafe.Pointer(&w)))
+				gr = *(*ppc_arch_gr_t)(unsafe.Pointer(&se))
+			} else {
+				e := int64(*(*uint32)(unsafe.Pointer(&w)))
+				gr = *(*ppc_arch_gr_t)(unsafe.Pointer(&e))
+			}
+		default:
+			panic("reflect: bad size in ppcReloadForRegister")
+	}
+
+	return *(*iword)(unsafe.Pointer(&gr))
+}
+
+// MakeFuncStubGo implements the ppc calling convention for
+// MakeFunc.  This should not be called.  It is exported so that
+// assembly code can call it.
+func MakeFuncStubGo(regs *ppc_regs, c *makeFuncImpl) {
+	ftyp := c.typ
+	gr := 0
+	fr := 0
+	ap := uintptr(regs.stack_args)
+
+	// See if the result requires a struct.  If it does, the first
+	// parameter is a pointer to the struct.
+	var ret_class, ret_class_2 ppc_arg_t
+	var ret_off_reg uintptr
+	var ret_type *rtype
+
+	switch len(ftyp.out) {
+	case 0:
+		ret_type = nil
+		ret_class, ret_class_2, ret_off_reg = ppc_empty, ppc_empty, 0
+	case 1:
+		ret_type = ftyp.out[0]
+		//ret_class, ret_off_reg = ppcClassifyReturn(ret_type)
+		ret_class, ret_class_2 = ppcClassify(ret_type)
+	default:
+		ret_type = nil
+		ret_class, ret_class_2, ret_off_reg = ppc_mem_ptr, ppc_empty, 0
+	}
+	in := make([]Value, 0, len(ftyp.in))
+	if ret_class == ppc_mem_ptr {
+		// We are returning a value in memory, which means
+		// that the first argument is a hidden parameter
+		// pointing to that return area.
+		gr++
+	}
+
+argloop:
+	for _, rt := range ftyp.in {
+		class, off_reg, off_slot := ppcClassifyParameter(rt)
+		fl := flag(rt.Kind()) << flagKindShift
+		switch class {
+		case ppc_empty:
+			v := Value{rt, nil, fl | flagIndir}
+			in = append(in, v)
+			continue argloop
+		case ppc_general_reg:
+			// Values stored in a general register are right
+			// aligned.
+			if gr < ppc_num_gr {
+				val := ppc_general_reg_val(regs, gr)
+				iw := unsafe.Pointer(val)
+				k := rt.Kind()
+				if k != Ptr && k != UnsafePointer {
+					ix := uintptr(unsafe.Pointer(&val))
+					ix += off_reg
+					iw = unsafe.Pointer(ix)
+					fl |= flagIndir
+				}
+				v := Value{rt, iw, fl}
+				in = append(in, v)
+				gr++
+			} else {
+				in, ap = ppc_add_stackreg(
+					in, ap, rt, off_slot)
+			}
+			continue argloop
+		case ppc_float_reg:
+			// In a register, floats are left aligned, but in a
+			// stack slot they are right aligned.
+			if fr < ppc_num_fr {
+				val := ppc_float_reg_val(regs, fr)
+				ix := uintptr(unsafe.Pointer(&val))
+				v := Value {
+					rt, unsafe.Pointer(unsafe.Pointer(ix)),
+					fl | flagIndir,
+				}
+				in = append(in, v)
+				fr++
+			} else {
+				in, ap = ppc_add_stackreg(
+					in, ap, rt, off_slot)
+			}
+			continue argloop
+		case ppc_mem_ptr:
+			if gr < ppc_num_gr && unsafe.Pointer(ppc_general_reg_val(regs, gr)) != nil {
+				// Register holding a pointer to memory.
+				val := ppc_general_reg_val(regs, gr)
+				v := Value{
+					rt, unsafe.Pointer(val), fl | flagIndir}
+				in = append(in, v)
+				gr++
+			} else {
+				// Stack slot holding a pointer to memory.
+				in, ap = ppc_add_memarg(in, ap, rt)
+			}
+			continue argloop
+		case ppc_slice:
+			if gr < ppc_num_gr {
+				// Register holding a pointer to memory.
+				val := ppc_general_reg_val(regs, gr)
+				cnt := ppc_general_reg_val(regs, gr+1)
+				cap := ppc_general_reg_val(regs, gr+2)
+
+				s := SliceHeader{val, int(cnt), int(cap)}
+				v := Value{
+					rt, unsafe.Pointer(&s), fl | flagIndir}
+				in = append(in, v)
+				gr+=3
+			} else {
+				// Stack slot holding a pointer to memory.
+				in, ap = ppc_add_memarg(in, ap, rt)
+			}
+			continue argloop
+		}
+		panic("reflect: argtype not handled in MakeFunc:argloop")
+	}
+
+	// All the real arguments have been found and turned into
+	// Values.  Call the real function.
+
+	out := c.call(in)
+
+	if len(out) != len(ftyp.out) {
+		panic("reflect: wrong return count from function created by MakeFunc")
+	}
+
+	for i, typ := range ftyp.out {
+		v := out[i]
+		if v.typ != typ {
+			panic(
+				"reflect: function created by MakeFunc using " +
+				funcName(c.fn) + " returned wrong type: have " +
+				out[i].typ.String() + " for " + typ.String())
+		}
+		if v.flag&flagRO != 0 {
+			panic(
+				"reflect: function created by MakeFunc using " +
+				 funcName(c.fn) + " returned value obtained " +
+				"from unexported field")
+		}
+	}
+
+	switch (ret_class) {
+	case ppc_general_reg, ppc_float_reg:
+		// Single return value in a general or floating point register.
+		v := out[0]
+		if (ret_class_2 == ppc_general_reg) {
+		   var buf [2]unsafe.Pointer
+		   ptr := unsafe.Pointer(&buf[0])
+		   off := uintptr(0)
+		   for i, typ := range ftyp.out {
+		       v := out[i]
+		       off = align(off, uintptr(typ.fieldAlign))
+		       addr := unsafe.Pointer(uintptr(ptr) + off)
+		       if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
+			  storeIword(addr, iword(v.val), typ.size)
+		       } else {
+		       	  memmove(addr, v.val, typ.size)
+		       }
+		       off += uintptr(typ.size)
+		   }
+		   regs.r3 = *(*ppc_arch_gr_t)(unsafe.Pointer(&buf[0]))
+		   regs.r4 = *(*ppc_arch_gr_t)(unsafe.Pointer(&buf[1]))
+		} else {
+		    w := v.iword()
+		    if v.Kind() != Ptr && v.Kind() != UnsafePointer {
+		       w = loadIword(unsafe.Pointer(w), v.typ.size)
+		       if (ret_off_reg != 0) {
+		       	  w = ppcReloadForRegister(ret_type, w, ret_off_reg)
+		    	  }
+		    }
+		    if (ret_class == ppc_float_reg) {
+		        regs.f1 = ppc_arch_fr_t(uintptr(w))
+		    } else {
+		        regs.r3 = ppc_arch_gr_t(uintptr(w))
+		    }
+		}
+
+	case ppc_mem_ptr:
+		// The address of the memory area was passed as a hidden
+		// parameter in %r2.  Multiple return values are always returned
+		// in an in-memory structure.
+		ptr := unsafe.Pointer(uintptr(regs.r3))
+		off := uintptr(0)
+		for i, typ := range ftyp.out {
+			v := out[i]
+			off = align(off, uintptr(typ.fieldAlign))
+			addr := unsafe.Pointer(uintptr(ptr) + off)
+			if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
+				storeIword(addr, iword(v.val), typ.size)
+			} else {
+				memmove(addr, v.val, typ.size)
+			}
+			off += typ.size
+		}
+
+	case ppc_empty:
+	}
+
+	return
+}
+
+// The ppc_add_stackreg function adds an argument passed on the
+// stack that could be passed in a register.
+func ppc_add_stackreg(
+	in []Value, ap uintptr, rt *rtype, offset uintptr) ([]Value, uintptr) {
+	// If we're not already at the beginning of a stack slot, round up to
+	// the beginning of the next one.
+	ap = align(ap, ppc_arch_stack_slot_align)
+	// If offset is > 0, the data is right aligned on the stack slot.
+	ap += offset
+
+	// We have to copy the argument onto the heap in case the
+	// function hangs onto the reflect.Value we pass it.
+	p := unsafe_New(rt)
+	memmove(p, unsafe.Pointer(ap), rt.size)
+
+	v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
+	in = append(in, v)
+	ap += rt.size
+	ap = align(ap, ppc_arch_stack_slot_align)
+
+	return in, ap
+}
+
+// The ppc_add_memarg function adds an argument passed in memory.
+func ppc_add_memarg(in []Value, ap uintptr, rt *rtype) ([]Value, uintptr) {
+	// If we're not already at the beginning of a stack slot,
+	// round up to the beginning of the next one.
+	ap = align(ap, ppc_arch_stack_slot_align)
+
+	// We have to copy the argument onto the heap in case the
+	// function hangs onto the reflect.Value we pass it.
+	p := unsafe_New(rt)
+	memmove(p, unsafe.Pointer(ap), rt.size)
+
+	v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
+	in = append(in, v)
+	ap += ppc_arch_stack_slot_align
+
+	return in, ap
+}
+
+// The ppc_general_reg_val function returns the value of integer register GR.
+func ppc_general_reg_val(regs *ppc_regs, gr int) uintptr {
+	var r ppc_arch_gr_t
+	switch gr {
+	case 0:
+		r = regs.r3
+	case 1:
+		r = regs.r4
+	case 2:
+		r = regs.r5
+	case 3:
+		r = regs.r6
+	case 4:
+		r = regs.r7
+	case 5:
+		r = regs.r8
+	case 6:
+		r = regs.r9
+	case 7:
+		r = regs.r10
+	default:
+		panic("ppc_general_reg_val: bad integer register")
+	}
+	return uintptr(r)
+}
+
+// The ppc_float_reg_val function returns the value of float register FR.
+func ppc_float_reg_val(regs *ppc_regs, fr int) uintptr {
+	var r ppc_arch_fr_t
+	switch fr {
+	case 0:
+		r = regs.f1
+	case 1:
+		r = regs.f2
+	case 2:
+		r = regs.f3
+	case 3:
+		r = regs.f4
+	case 4:
+		r = regs.f5
+	case 5:
+		r = regs.f6
+	case 6:
+		r = regs.f7
+	case 7:
+		r = regs.f8
+	case 8:
+		r = regs.f9
+	case 9:
+		r = regs.f10
+	case 10:
+		r = regs.f11
+	case 11:
+		r = regs.f12
+	case 12:
+		r = regs.f13
+	default:
+		panic("ppc_float_reg_val: bad floating point register")
+	}
+	return uintptr(r)
+}