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 <labo...@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
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" (®s.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(®s, closure);
+ /* MakeFunc functions can no longer call recover. */
+ __go_makefunc_returning();
+ /* Restore all possible return registers. */
+
+ asm volatile ("ld\t3,0(%0)" : : "a" (®s.r3) : "r3" );
+ asm volatile ("ld\t4,0(%0)" : : "a" (®s.r4) : "r4" );
+ asm volatile ("lfd\t1,0(%0)" : : "a" (®s.f1) : "fr1" );
+ asm volatile ("lfd\t2,0(%0)" : : "a" (®s.f2) : "fr2" );
+ asm volatile ("lfd\t3,0(%0)" : : "a" (®s.f3) : "fr3" );
+ asm volatile ("lfd\t4,0(%0)" : : "a" (®s.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)
+}