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" (&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)
+}

Reply via email to