From patchwork Tue Jan 6 15:37:56 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Lynn A. Boger" X-Patchwork-Id: 425707 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id F19F91400B7 for ; Wed, 7 Jan 2015 02:38:18 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; q= dns; s=default; b=PW5fsc6tPWND9vIYIU8zIXVfJxSPqFGwZolx2EHy9dL3wc 6qWFkd3RnBUKzDr5r0O7O4RZfHsXuPDes+MTK3ZbZHVP5Ym11TklGoOjVne8NLQ9 TlPL95l4mS3Mktj2PW616o5Hb6doohz58cIBYXriibDPPH+p4vmXqLyjXE5Co= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:subject:content-type; s= default; bh=bFibYDgrFCy30i96UQ8o58sX0Ws=; b=su6vW3mKHGqblPhJlrEo wlTNb4HUoJWjPYQwudauLPccl0/8U0zsZB/accckYxB3kqd+44TwDE35+1jTgw7M 5/bJSwz28jthctceg64EfKx6Jp7t5wuAzv3qhLCy1vGb4BSJA+kdOGepRYWmuxOP +Pxg3MsfDXLZ7AOINVzNg48= Received: (qmail 22902 invoked by alias); 6 Jan 2015 15:38:09 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 22889 invoked by uid 89); 6 Jan 2015 15:38:08 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: e36.co.us.ibm.com Received: from e36.co.us.ibm.com (HELO e36.co.us.ibm.com) (32.97.110.154) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Tue, 06 Jan 2015 15:38:01 +0000 Received: from /spool/local by e36.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 6 Jan 2015 08:37:59 -0700 Received: from d03dlp02.boulder.ibm.com (9.17.202.178) by e36.co.us.ibm.com (192.168.1.136) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 6 Jan 2015 08:37:58 -0700 Received: from b03cxnp07028.gho.boulder.ibm.com (b03cxnp07028.gho.boulder.ibm.com [9.17.130.15]) by d03dlp02.boulder.ibm.com (Postfix) with ESMTP id AB0C33E4003F for ; Tue, 6 Jan 2015 08:37:57 -0700 (MST) Received: from d03av05.boulder.ibm.com (d03av05.boulder.ibm.com [9.17.195.85]) by b03cxnp07028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id t06FakKK31850646 for ; Tue, 6 Jan 2015 08:36:46 -0700 Received: from d03av05.boulder.ibm.com (localhost [127.0.0.1]) by d03av05.boulder.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id t06Fbv02027389 for ; Tue, 6 Jan 2015 08:37:57 -0700 Received: from oc2602623110.ibm.com (oc2602623110.ibm.com.rchland.ibm.com [9.10.86.28]) by d03av05.boulder.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id t06FbuPX027317; Tue, 6 Jan 2015 08:37:57 -0700 Message-ID: <54AC0154.7020700@linux.vnet.ibm.com> Date: Tue, 06 Jan 2015 09:37:56 -0600 From: "Lynn A. Boger" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.3.0 MIME-Version: 1.0 To: gcc-patches , "gofrontend-dev@googlegroups.com" Subject: [PATCH 1/2, libgo] Add reflection support to gccgo for ppc64, ppc64le in gcc 4.9 X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 15010615-0021-0000-0000-0000078A65F8 X-IsSubscribed: yes 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 * 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()<