summaryrefslogtreecommitdiff
path: root/libgo/go/reflect
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r--libgo/go/reflect/makefunc.go4
-rw-r--r--libgo/go/reflect/makefunc_s390.c86
-rw-r--r--libgo/go/reflect/makefuncgo_s390.go453
-rw-r--r--libgo/go/reflect/makefuncgo_s390x.go435
4 files changed, 976 insertions, 2 deletions
diff --git a/libgo/go/reflect/makefunc.go b/libgo/go/reflect/makefunc.go
index 977aacfd438..eb4589c6ce9 100644
--- a/libgo/go/reflect/makefunc.go
+++ b/libgo/go/reflect/makefunc.go
@@ -61,7 +61,7 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
var code uintptr
var ffi *ffiData
switch runtime.GOARCH {
- case "amd64", "386":
+ case "amd64", "386", "s390", "s390x":
// Indirect Go func value (dummy) to obtain actual
// code address. (A Go func value is a pointer to a C
// function pointer. http://golang.org/s/go11func.)
@@ -159,7 +159,7 @@ func makeValueMethod(v Value) Value {
}
switch runtime.GOARCH {
- case "amd64", "386":
+ case "amd64", "386", "s390", "s390x":
// Indirect Go func value (dummy) to obtain actual
// code address. (A Go func value is a pointer to a C
// function pointer. http://golang.org/s/go11func.)
diff --git a/libgo/go/reflect/makefunc_s390.c b/libgo/go/reflect/makefunc_s390.c
new file mode 100644
index 00000000000..78a960ca2f6
--- /dev/null
+++ b/libgo/go/reflect/makefunc_s390.c
@@ -0,0 +1,86 @@
+// Copyright 2014 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"
+
+#ifdef __s390x__
+# define S390_GO_USE_64_BIT_ABI 1
+# define S390_GO_S390X_ARGS , double f4, double f6
+# define S390_GO_S390X_FIELDS double f4; double f6;
+ extern void S390xMakeFuncStubGo(void *, void *)
+ asm ("reflect.S390xMakeFuncStubGo");
+# define S390_GO_MakeFuncStubGo(r, c) S390xMakeFuncStubGo((r), (c))
+#else
+# define S390_GO_USE_64_BIT_ABI 0
+# define S390_GO_S390X_ARGS
+# define S390_GO_S390X_FIELDS
+ extern void S390MakeFuncStubGo(void *, void *)
+ asm ("reflect.S390MakeFuncStubGo");
+# define S390_GO_MakeFuncStubGo(r, c) S390MakeFuncStubGo((r), (c))
+ /* Needed to make the unused 64 bit abi conditional code compile. */
+# define f4 f0
+# define f6 f2
+#endif
+
+/* Structure to store all registers used for parameter passing. */
+typedef struct
+{
+ long r2;
+ long r3;
+ long r4;
+ long r5;
+ long r6;
+ /* Pointer to non-register arguments on the stack. */
+ long stack_args;
+ double f0;
+ double f2;
+ S390_GO_S390X_FIELDS
+} s390Regs;
+
+void
+makeFuncStub(long r2, long r3, long r4, long r5, long r6,
+ unsigned long stack_args, double f0, double f2
+ S390_GO_S390X_ARGS)
+ asm ("reflect.makeFuncStub");
+
+void
+makeFuncStub(long r2, long r3, long r4, long r5, long r6,
+ unsigned long stack_args, double f0, double f2
+ S390_GO_S390X_ARGS)
+{
+ s390Regs regs;
+ void *closure;
+
+ /* Store the registers in a structure that is passed on to the Go stub
+ function. */
+ regs.r2 = r2;
+ regs.r3 = r3;
+ regs.r4 = r4;
+ regs.r5 = r5;
+ regs.r6 = r6;
+ regs.stack_args = (long)&stack_args;
+ regs.f0 = f0;
+ regs.f2 = f2;
+ if (S390_GO_USE_64_BIT_ABI) {
+ regs.f4 = f4;
+ regs.f6 = f6;
+ }
+ /* For MakeFunc functions that call recover. */
+ __go_makefunc_can_recover(__builtin_return_address(0));
+ /* Call the Go stub function. */
+ closure = __go_get_closure();
+ S390_GO_MakeFuncStubGo(&regs, closure);
+ /* MakeFunc functions can no longer call recover. */
+ __go_makefunc_returning();
+ /* Restore all possible return registers. */
+ if (S390_GO_USE_64_BIT_ABI) {
+ asm volatile ("lg\t%%r2,0(%0)" : : "a" (&regs.r2) : "r2" );
+ asm volatile ("ld\t%%f0,0(%0)" : : "a" (&regs.f0) : "f0" );
+ } else {
+ asm volatile ("l\t%%r2,0(%0)" : : "a" (&regs.r2) : "r2" );
+ asm volatile ("l\t%%r3,0(%0)" : : "a" (&regs.r3) : "r3" );
+ asm volatile ("ld\t%%f0,0(%0)" : : "a" (&regs.f0) : "f0" );
+ }
+}
diff --git a/libgo/go/reflect/makefuncgo_s390.go b/libgo/go/reflect/makefuncgo_s390.go
new file mode 100644
index 00000000000..ff22add81a1
--- /dev/null
+++ b/libgo/go/reflect/makefuncgo_s390.go
@@ -0,0 +1,453 @@
+// Copyright 2014 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 s390 implementation.
+
+package reflect
+
+import "unsafe"
+
+// Convenience types and constants.
+const s390_arch_stack_slot_align uintptr = 4
+const s390_num_gr = 5
+const s390_num_fr = 2
+
+type s390_arch_gr_t uint32
+type s390_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 s390_regs struct {
+ r2 s390_arch_gr_t
+ r3 s390_arch_gr_t
+ r4 s390_arch_gr_t
+ r5 s390_arch_gr_t
+ r6 s390_arch_gr_t
+ stack_args s390_arch_gr_t
+ f0 s390_arch_fr_t
+ f2 s390_arch_fr_t
+}
+
+// Argument classifications that arise for Go types.
+type s390_arg_t int
+
+const (
+ s390_general_reg s390_arg_t = iota
+ s390_general_reg_pair
+ s390_float_reg
+ // Argument passed as a pointer to an in-memory value.
+ s390_mem_ptr
+ s390_empty
+)
+
+// s390ClassifyParameter returns the register class needed to
+// pass the value of type TYP. s390_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 s390ClassifyParameter(typ *rtype) (s390_arg_t, uintptr, uintptr) {
+ offset := s390_arch_stack_slot_align - typ.Size()
+ if typ.Size() > s390_arch_stack_slot_align {
+ offset = 0
+ }
+ switch typ.Kind() {
+ default:
+ panic("internal error--unknown kind in s390ClassifyParameter")
+ case Bool, Int, Int8, Int16, Int32, Uint, Uint8, Uint16, Uint32:
+ return s390_general_reg, offset, offset
+ case Int64, Uint64:
+ return s390_general_reg_pair, 0, 0
+ case Uintptr, Chan, Func, Map, Ptr, UnsafePointer:
+ return s390_general_reg, 0, 0
+ case Float32, Float64:
+ return s390_float_reg, 0, offset
+ case Complex64, Complex128:
+ // Complex numbers are passed by reference.
+ return s390_mem_ptr, 0, 0
+ case Array, Struct:
+ var ityp *rtype
+ var length int
+
+ if typ.Size() == 0 {
+ return s390_empty, 0, 0
+ }
+ switch typ.Size() {
+ default:
+ // Pointer to memory.
+ return s390_mem_ptr, 0, 0
+ case 1, 2:
+ // Pass in an integer register.
+ return s390_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 := s390ClassifyParameter(ityp)
+ if class == s390_float_reg {
+ // The array (stored in a structure) or struct
+ // is "equivalent to a floating point type" as
+ // defined in the S390 Abi. Note that this
+ // can only be the case in the case 4 of the
+ // switch above.
+ return s390_float_reg, off_reg, off_slot
+ }
+ }
+ switch typ.Size() {
+ case 4:
+ return s390_general_reg, offset, offset
+ case 8:
+ return s390_general_reg_pair, 0, 0
+ default:
+ return s390_general_reg, 0, 0
+ }
+ case Interface, String:
+ // Structure of size 8.
+ return s390_general_reg_pair, 0, 0
+
+ case Slice:
+ return s390_mem_ptr, 0, 0
+ }
+}
+
+// s390ClassifyReturn 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 s390ClassifyReturn(typ *rtype) (s390_arg_t, uintptr) {
+ offset := s390_arch_stack_slot_align - typ.Size()
+ if typ.Size() > s390_arch_stack_slot_align {
+ offset = 0
+ }
+ switch typ.Kind() {
+ default:
+ panic("internal error--unknown kind in s390ClassifyReturn")
+ case Bool, Int, Int8, Int16, Int32,
+ Uint, Uint8, Uint16, Uint32, Uintptr:
+
+ return s390_general_reg, offset
+ case Int64, Uint64:
+ return s390_general_reg_pair, 0
+ case Chan, Func, Map, Ptr, UnsafePointer:
+ return s390_general_reg, 0
+ case Float32, Float64:
+ return s390_float_reg, 0
+ case Complex64, Complex128:
+ return s390_mem_ptr, 0
+ case Interface, Slice, String:
+ return s390_mem_ptr, 0
+ case Array, Struct:
+ if typ.size == 0 {
+ return s390_empty, 0
+ }
+ // No optimization is done for returned structures and arrays.
+ return s390_mem_ptr, 0
+ }
+}
+
+// Given a value of type *rtype left aligned in an unsafe.Pointer,
+// 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 s390ReloadForRegister(typ *rtype, w uintptr, offset uintptr) uintptr {
+ var do_sign_extend bool = false
+ var gr s390_arch_gr_t
+
+ switch typ.Kind() {
+ case Int, Int8, Int16, Int32:
+ do_sign_extend = true
+ default:
+ // Handle all other cases in the next switch.
+ }
+ switch typ.size {
+ case 1:
+ if do_sign_extend == true {
+ se := int32(*(*int8)(unsafe.Pointer(&w)))
+ gr = *(*s390_arch_gr_t)(unsafe.Pointer(&se))
+ } else {
+ e := int32(*(*uint8)(unsafe.Pointer(&w)))
+ gr = *(*s390_arch_gr_t)(unsafe.Pointer(&e))
+ }
+ case 2:
+ if do_sign_extend == true {
+ se := int32(*(*int16)(unsafe.Pointer(&w)))
+ gr = *(*s390_arch_gr_t)(unsafe.Pointer(&se))
+ } else {
+ e := int32(*(*uint16)(unsafe.Pointer(&w)))
+ gr = *(*s390_arch_gr_t)(unsafe.Pointer(&e))
+ }
+ default:
+ panic("reflect: bad size in s390ReloadForRegister")
+ }
+
+ return *(*uintptr)(unsafe.Pointer(&gr))
+}
+
+// MakeFuncStubGo implements the s390 calling convention for
+// MakeFunc. This should not be called. It is exported so that
+// assembly code can call it.
+func S390MakeFuncStubGo(regs *s390_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 s390_arg_t
+ var ret_off_reg uintptr
+ var ret_type *rtype
+
+ switch len(ftyp.out) {
+ case 0:
+ ret_type = nil
+ ret_class, ret_off_reg = s390_empty, 0
+ case 1:
+ ret_type = ftyp.out[0]
+ ret_class, ret_off_reg = s390ClassifyReturn(ret_type)
+ default:
+ ret_type = nil
+ ret_class, ret_off_reg = s390_mem_ptr, 0
+ }
+ in := make([]Value, 0, len(ftyp.in))
+ if ret_class == s390_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 := s390ClassifyParameter(rt)
+ fl := flag(rt.Kind()) << flagKindShift
+ switch class {
+ case s390_empty:
+ v := Value{rt, nil, fl | flagIndir}
+ in = append(in, v)
+ continue argloop
+ case s390_general_reg:
+ // Values stored in a general register are right
+ // aligned.
+ if gr < s390_num_gr {
+ val := s390_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 = s390_add_stackreg(
+ in, ap, rt, off_slot)
+ }
+ continue argloop
+ case s390_general_reg_pair:
+ // 64-bit integers and structs are passed in a register
+ // pair.
+ if gr+1 < s390_num_gr {
+ val := uint64(s390_general_reg_val(regs, gr))<<32 + uint64(s390_general_reg_val(regs, gr+1))
+ iw := unsafe.Pointer(&val)
+ v := Value{rt, iw, fl | flagIndir}
+ in = append(in, v)
+ gr += 2
+ } else {
+ in, ap = s390_add_stackreg(in, ap, rt, off_slot)
+ gr = s390_num_gr
+ }
+ continue argloop
+ case s390_float_reg:
+ // In a register, floats are left aligned, but in a
+ // stack slot they are right aligned.
+ if fr < s390_num_fr {
+ val := s390_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 = s390_add_stackreg(
+ in, ap, rt, off_slot)
+ }
+ continue argloop
+ case s390_mem_ptr:
+ if gr < s390_num_gr {
+ // Register holding a pointer to memory.
+ val := s390_general_reg_val(regs, gr)
+ v := Value{
+ rt, unsafe.Pointer(uintptr(val)),
+ fl | flagIndir}
+ in = append(in, v)
+ gr++
+ } else {
+ // Stack slot holding a pointer to memory.
+ in, ap = s390_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 s390_general_reg, s390_float_reg, s390_general_reg_pair:
+ // Single return value in a general or floating point register.
+ v := out[0]
+ var w uintptr
+ if v.Kind() == Ptr || v.Kind() == UnsafePointer {
+ w = uintptr(v.pointer())
+ } else {
+ w = uintptr(loadScalar(v.ptr, v.typ.size))
+ if ret_off_reg != 0 {
+ w = s390ReloadForRegister(
+ ret_type, w, ret_off_reg)
+ }
+ }
+ if ret_class == s390_float_reg {
+ regs.f0 = s390_arch_fr_t(uintptr(w))
+ } else if ret_class == s390_general_reg {
+ regs.r2 = s390_arch_gr_t(uintptr(w))
+ } else {
+ regs.r2 = s390_arch_gr_t(uintptr(w) >> 32)
+ regs.r3 = s390_arch_gr_t(uintptr(w) & 0xffffffff)
+ }
+
+ case s390_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.r2))
+ 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) {
+ *(*unsafe.Pointer)(addr) = v.ptr
+ } else {
+ memmove(addr, v.ptr, typ.size)
+ }
+ off += typ.size
+ }
+
+ case s390_empty:
+ }
+
+ return
+}
+
+// The s390_add_stackreg function adds an argument passed on the
+// stack that could be passed in a register.
+func s390_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, s390_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, s390_arch_stack_slot_align)
+
+ return in, ap
+}
+
+// The s390_add_memarg function adds an argument passed in memory.
+func s390_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, s390_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)(unsafe.Pointer(ap)), rt.size)
+
+ v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
+ in = append(in, v)
+ ap += s390_arch_stack_slot_align
+
+ return in, ap
+}
+
+// The s390_general_reg_val function returns the value of integer register GR.
+func s390_general_reg_val(regs *s390_regs, gr int) s390_arch_gr_t {
+ switch gr {
+ case 0:
+ return regs.r2
+ case 1:
+ return regs.r3
+ case 2:
+ return regs.r4
+ case 3:
+ return regs.r5
+ case 4:
+ return regs.r6
+ default:
+ panic("s390_general_reg_val: bad integer register")
+ }
+}
+
+// The s390_float_reg_val function returns the value of float register FR.
+func s390_float_reg_val(regs *s390_regs, fr int) uintptr {
+ var r s390_arch_fr_t
+ switch fr {
+ case 0:
+ r = regs.f0
+ case 1:
+ r = regs.f2
+ default:
+ panic("s390_float_reg_val: bad floating point register")
+ }
+ return uintptr(r)
+}
diff --git a/libgo/go/reflect/makefuncgo_s390x.go b/libgo/go/reflect/makefuncgo_s390x.go
new file mode 100644
index 00000000000..a0a5567f3b9
--- /dev/null
+++ b/libgo/go/reflect/makefuncgo_s390x.go
@@ -0,0 +1,435 @@
+// Copyright 2014 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 s390x implementation.
+
+package reflect
+
+import "unsafe"
+
+// Convenience types and constants.
+const s390x_arch_stack_slot_align uintptr = 8
+const s390x_num_gr = 5
+const s390x_num_fr = 4
+
+type s390x_arch_gr_t uint64
+type s390x_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 s390x_regs struct {
+ r2 s390x_arch_gr_t
+ r3 s390x_arch_gr_t
+ r4 s390x_arch_gr_t
+ r5 s390x_arch_gr_t
+ r6 s390x_arch_gr_t
+ stack_args s390x_arch_gr_t
+ f0 s390x_arch_fr_t
+ f2 s390x_arch_fr_t
+ f4 s390x_arch_fr_t
+ f6 s390x_arch_fr_t
+}
+
+// Argument classifications that arise for Go types.
+type s390x_arg_t int
+
+const (
+ s390x_general_reg s390x_arg_t = iota
+ s390x_float_reg
+ // Argument passed as a pointer to an in-memory value.
+ s390x_mem_ptr
+ s390x_empty
+)
+
+// s390xClassifyParameter returns the register class needed to
+// pass the value of type TYP. s390x_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 s390xClassifyParameter(typ *rtype) (s390x_arg_t, uintptr, uintptr) {
+ offset := s390x_arch_stack_slot_align - typ.Size()
+ switch typ.Kind() {
+ default:
+ panic("internal error--unknown kind in s390xClassifyParameter")
+ case Bool, Int, Int8, Int16, Int32, Uint, Uint8, Uint16, Uint32:
+ return s390x_general_reg, offset, offset
+ case Int64, Uint64, Uintptr, Chan, Func, Map, Ptr, UnsafePointer:
+ return s390x_general_reg, 0, 0
+ case Float32, Float64:
+ return s390x_float_reg, 0, offset
+ case Complex64, Complex128:
+ // Complex numbers are passed by reference.
+ return s390x_mem_ptr, 0, 0
+ case Array, Struct:
+ var ityp *rtype
+ var length int
+
+ if typ.Size() == 0 {
+ return s390x_empty, 0, 0
+ }
+ switch typ.Size() {
+ default:
+ // Pointer to memory.
+ return s390x_mem_ptr, 0, 0
+ case 1, 2:
+ // Pass in an integer register.
+ return s390x_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 := s390xClassifyParameter(ityp)
+ if class == s390x_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 s390x_float_reg, off_reg, off_slot
+ }
+ }
+ // Otherwise pass in an integer register.
+ switch typ.Size() {
+ case 4, 8:
+ return s390x_general_reg, offset, offset
+ default:
+ return s390x_general_reg, 0, 0
+ }
+ case Interface, Slice, String:
+ return s390x_mem_ptr, 0, 0
+ }
+}
+
+// s390xClassifyReturn 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 s390xClassifyReturn(typ *rtype) (s390x_arg_t, uintptr) {
+ offset := s390x_arch_stack_slot_align - typ.Size()
+ switch typ.Kind() {
+ default:
+ panic("internal error--unknown kind in s390xClassifyReturn")
+ case Bool, Int, Int8, Int16, Int32, Int64,
+ Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
+
+ return s390x_general_reg, offset
+ case Chan, Func, Map, Ptr, UnsafePointer:
+ return s390x_general_reg, 0
+ case Float32, Float64:
+ return s390x_float_reg, 0
+ case Complex64, Complex128:
+ return s390x_mem_ptr, 0
+ case Interface, Slice, String:
+ return s390x_mem_ptr, 0
+ case Array, Struct:
+ if typ.size == 0 {
+ return s390x_empty, 0
+ }
+ // No optimization is done for returned structures and arrays.
+ return s390x_mem_ptr, 0
+ }
+}
+
+// Given a value of type *rtype left aligned in an unsafe.Pointer,
+// 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 s390xReloadForRegister(typ *rtype, w uintptr, offset uintptr) uintptr {
+ var do_sign_extend bool = false
+ var gr s390x_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 = *(*s390x_arch_gr_t)(unsafe.Pointer(&se))
+ } else {
+ e := int64(*(*uint8)(unsafe.Pointer(&w)))
+ gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e))
+ }
+ case 2:
+ if do_sign_extend == true {
+ se := int64(*(*int16)(unsafe.Pointer(&w)))
+ gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&se))
+ } else {
+ e := int64(*(*uint16)(unsafe.Pointer(&w)))
+ gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e))
+ }
+ case 4:
+ if do_sign_extend == true {
+ se := int64(*(*int32)(unsafe.Pointer(&w)))
+ gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&se))
+ } else {
+ e := int64(*(*uint32)(unsafe.Pointer(&w)))
+ gr = *(*s390x_arch_gr_t)(unsafe.Pointer(&e))
+ }
+ default:
+ panic("reflect: bad size in s390xReloadForRegister")
+ }
+
+ return *(*uintptr)(unsafe.Pointer(&gr))
+}
+
+// MakeFuncStubGo implements the s390x calling convention for
+// MakeFunc. This should not be called. It is exported so that
+// assembly code can call it.
+func S390xMakeFuncStubGo(regs *s390x_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 s390x_arg_t
+ var ret_off_reg uintptr
+ var ret_type *rtype
+
+ switch len(ftyp.out) {
+ case 0:
+ ret_type = nil
+ ret_class, ret_off_reg = s390x_empty, 0
+ case 1:
+ ret_type = ftyp.out[0]
+ ret_class, ret_off_reg = s390xClassifyReturn(ret_type)
+ default:
+ ret_type = nil
+ ret_class, ret_off_reg = s390x_mem_ptr, 0
+ }
+ in := make([]Value, 0, len(ftyp.in))
+ if ret_class == s390x_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 := s390xClassifyParameter(rt)
+ fl := flag(rt.Kind()) << flagKindShift
+ switch class {
+ case s390x_empty:
+ v := Value{rt, nil, fl | flagIndir}
+ in = append(in, v)
+ continue argloop
+ case s390x_general_reg:
+ // Values stored in a general register are right
+ // aligned.
+ if gr < s390x_num_gr {
+ val := s390x_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 = s390x_add_stackreg(
+ in, ap, rt, off_slot)
+ }
+ continue argloop
+ case s390x_float_reg:
+ // In a register, floats are left aligned, but in a
+ // stack slot they are right aligned.
+ if fr < s390x_num_fr {
+ val := s390x_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 = s390x_add_stackreg(
+ in, ap, rt, off_slot)
+ }
+ continue argloop
+ case s390x_mem_ptr:
+ if gr < s390x_num_gr {
+ // Register holding a pointer to memory.
+ val := s390x_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 = s390x_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 s390x_general_reg, s390x_float_reg:
+ // Single return value in a general or floating point register.
+ v := out[0]
+ var w uintptr
+ if v.Kind() == Ptr || v.Kind() == UnsafePointer {
+ w = uintptr(v.pointer())
+ } else {
+ w = uintptr(loadScalar(v.ptr, v.typ.size))
+ if ret_off_reg != 0 {
+ w = s390xReloadForRegister(
+ ret_type, w, ret_off_reg)
+ }
+ }
+ if ret_class == s390x_float_reg {
+ regs.f0 = s390x_arch_fr_t(w)
+ } else {
+ regs.r2 = s390x_arch_gr_t(w)
+ }
+
+ case s390x_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.r2))
+ 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) {
+ *(*unsafe.Pointer)(addr) = v.ptr
+ } else {
+ memmove(addr, v.ptr, typ.size)
+ }
+ off += typ.size
+ }
+
+ case s390x_empty:
+ }
+
+ return
+}
+
+// The s390x_add_stackreg function adds an argument passed on the
+// stack that could be passed in a register.
+func s390x_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, s390x_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, s390x_arch_stack_slot_align)
+
+ return in, ap
+}
+
+// The s390x_add_memarg function adds an argument passed in memory.
+func s390x_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, s390x_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)(unsafe.Pointer(ap)), rt.size)
+
+ v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir}
+ in = append(in, v)
+ ap += s390x_arch_stack_slot_align
+
+ return in, ap
+}
+
+// The s390x_general_reg_val function returns the value of integer register GR.
+func s390x_general_reg_val(regs *s390x_regs, gr int) uintptr {
+ var r s390x_arch_gr_t
+ switch gr {
+ case 0:
+ r = regs.r2
+ case 1:
+ r = regs.r3
+ case 2:
+ r = regs.r4
+ case 3:
+ r = regs.r5
+ case 4:
+ r = regs.r6
+ default:
+ panic("s390x_general_reg_val: bad integer register")
+ }
+ return uintptr(r)
+}
+
+// The s390x_float_reg_val function returns the value of float register FR.
+func s390x_float_reg_val(regs *s390x_regs, fr int) uintptr {
+ var r s390x_arch_fr_t
+ switch fr {
+ case 0:
+ r = regs.f0
+ case 1:
+ r = regs.f2
+ case 2:
+ r = regs.f4
+ case 3:
+ r = regs.f6
+ default:
+ panic("s390x_float_reg_val: bad floating point register")
+ }
+ return uintptr(r)
+}