diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s index 1bd4b1e1c8..b6c0aa5035 100644 --- a/src/cmd/asm/internal/asm/testdata/ppc64.s +++ b/src/cmd/asm/internal/asm/testdata/ppc64.s @@ -41,8 +41,8 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0 MOVDBR (R3)(R4), R5 // 7ca41c28 MOVWBR (R3)(R4), R5 // 7ca41c2c MOVHBR (R3)(R4), R5 // 7ca41e2c - MOVD $foo+4009806848(FP), R5 // 3fe1ef0138bfcc20 - MOVD $foo(SB), R5 // 3fe0000038bf0000 + MOVD $foo+4009806848(FP), R5 // 3ca1ef0138a5cc20 + MOVD $foo(SB), R5 // 3ca0000038a50000 MOVDU 8(R3), R4 // e8830009 MOVDU (R3)(R4), R5 // 7ca4186a diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index 69f967acfd..316959f62d 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -2220,7 +2220,7 @@ func (c *ctxt9) opform(insn uint32) int { // Encode instructions and create relocation for accessing s+d according to the // instruction op with source or destination (as appropriate) register reg. -func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32) (o1, o2 uint32) { +func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32, reuse bool) (o1, o2 uint32) { if c.ctxt.Headtype == objabi.Haix { // Every symbol access must be made via a TOC anchor. c.ctxt.Diag("symbolAccess called for %s", s.Name) @@ -2232,8 +2232,15 @@ func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32) (o1, o2 } else { base = REG_R0 } - o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0) - o2 = AOP_IRR(op, uint32(reg), REGTMP, 0) + // If reg can be reused when computing the symbol address, + // use it instead of REGTMP. + if !reuse { + o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0) + o2 = AOP_IRR(op, uint32(reg), REGTMP, 0) + } else { + o1 = AOP_IRR(OP_ADDIS, uint32(reg), base, 0) + o2 = AOP_IRR(op, uint32(reg), uint32(reg), 0) + } rel := obj.Addrel(c.cursym) rel.Off = int32(c.pc) rel.Siz = 8 @@ -2877,14 +2884,14 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { switch p.From.Name { case obj.NAME_EXTERN, obj.NAME_STATIC: // Load a 32 bit constant, or relocation depending on if a symbol is attached - o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, OP_ADDI) + o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, OP_ADDI, true) default: if r == 0 { r = c.getimpliedreg(&p.From, p) } // Add a 32 bit offset to a register. - o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(int32(v)))) - o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(v)) + o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(int32(v)))) + o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), uint32(p.To.Reg), uint32(v)) } case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */ @@ -3043,10 +3050,10 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { if r == 0 { r = c.getimpliedreg(&p.From, p) } - o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v))) - o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), REGTMP, uint32(v)) + o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v))) + o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v)) - // Sign extend MOVB operations. This is ignored for other cases (o.size == 8). + // Sign extend MOVB if needed o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0) case 40: /* word */ @@ -3404,7 +3411,8 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { if c.opform(inst) == DS_FORM && v&0x3 != 0 { log.Fatalf("invalid offset for DS form load/store %v", p) } - o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst) + // Can't reuse base for store instructions. + o1, o2 = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst, false) case 75: // 32 bit offset symbol loads (got/toc/addr) v := p.From.Offset @@ -3432,10 +3440,11 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) { rel.Type = objabi.R_ADDRPOWER_TOCREL_DS } default: - o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst) + reuseBaseReg := p.As != AFMOVD && p.As != AFMOVS + // Reuse To.Reg as base register if not FP move. + o1, o2 = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst, reuseBaseReg) } - // Sign extend MOVB operations. This is ignored for other cases (o.size == 8). o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0) case 79: diff --git a/src/runtime/cgo/gcc_mmap.c b/src/runtime/cgo/gcc_mmap.c index e6a621d5a3..698a7e3cd2 100644 --- a/src/runtime/cgo/gcc_mmap.c +++ b/src/runtime/cgo/gcc_mmap.c @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build linux,amd64 linux,arm64 +// +build linux,amd64 linux,arm64 linux,ppc64le #include #include diff --git a/src/runtime/cgo/gcc_sigaction.c b/src/runtime/cgo/gcc_sigaction.c index 890008e327..dd283151f1 100644 --- a/src/runtime/cgo/gcc_sigaction.c +++ b/src/runtime/cgo/gcc_sigaction.c @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build linux,amd64 linux,arm64 +// +build linux,amd64 linux,arm64 linux,ppc64le #include #include diff --git a/src/runtime/cgo/sigaction.go b/src/runtime/cgo/sigaction.go index ee63ea4c09..692fd2675f 100644 --- a/src/runtime/cgo/sigaction.go +++ b/src/runtime/cgo/sigaction.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) -// +build linux,amd64 freebsd,amd64 linux,arm64 +//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) || (linux && ppc64le) +// +build linux,amd64 freebsd,amd64 linux,arm64 linux,ppc64le package cgo @@ -11,8 +11,8 @@ package cgo import _ "unsafe" // When using cgo, call the C library for sigaction, so that we call into -// any sanitizer interceptors. This supports using the memory -// sanitizer with Go programs. The memory sanitizer only applies to +// any sanitizer interceptors. This supports using the sanitizers +// with Go programs. The thread and memory sanitizers only apply to // C/C++ code; this permits that code to see the Go runtime's existing signal // handlers when registering new signal handlers for the process. diff --git a/src/runtime/cgo_sigaction.go b/src/runtime/cgo_sigaction.go index 15690ecb0b..6099d1b746 100644 --- a/src/runtime/cgo_sigaction.go +++ b/src/runtime/cgo_sigaction.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Support for memory sanitizer. See runtime/cgo/sigaction.go. +// Support for sanitizers. See runtime/cgo/sigaction.go. -//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) -// +build linux,amd64 freebsd,amd64 linux,arm64 +//go:build (linux && amd64) || (freebsd && amd64) || (linux && arm64) || (linux && ppc64le) +// +build linux,amd64 freebsd,amd64 linux,arm64 linux,ppc64le package runtime diff --git a/src/runtime/sigaction.go b/src/runtime/sigaction.go index 76f37b1b53..30050efcc7 100644 --- a/src/runtime/sigaction.go +++ b/src/runtime/sigaction.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (linux && !amd64 && !arm64) || (freebsd && !amd64) -// +build linux,!amd64,!arm64 freebsd,!amd64 +//go:build (linux && !amd64 && !arm64 && !ppc64le) || (freebsd && !amd64) +// +build linux,!amd64,!arm64,!ppc64le freebsd,!amd64 package runtime diff --git a/src/runtime/stubs_ppc64.go b/src/runtime/stubs_ppc64.go new file mode 100644 index 0000000000..f692947109 --- /dev/null +++ b/src/runtime/stubs_ppc64.go @@ -0,0 +1,16 @@ +// Copyright 2021 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. + +//go:build linux +// +build linux + +package runtime + +// Called from assembly only; declared for go vet. +func load_g() +func save_g() +func reginit() + +//go:noescape +func callCgoSigaction(sig uintptr, new, old *sigactiont) int32 diff --git a/src/runtime/stubs_ppc64x.go b/src/runtime/stubs_ppc64le.go similarity index 83% rename from src/runtime/stubs_ppc64x.go rename to src/runtime/stubs_ppc64le.go index 0841b413fd..5b733136e3 100644 --- a/src/runtime/stubs_ppc64x.go +++ b/src/runtime/stubs_ppc64le.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build ppc64 || ppc64le -// +build ppc64 ppc64le - package runtime // Called from assembly only; declared for go vet. diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s index 75da130357..46387288d5 100644 --- a/src/runtime/sys_linux_ppc64x.s +++ b/src/runtime/sys_linux_ppc64x.s @@ -336,6 +336,26 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36 MOVW R3, ret+32(FP) RET +#ifdef GOARCH_ppc64le +// Call the function stored in _cgo_sigaction using the GCC calling convention. +TEXT runtime·callCgoSigaction(SB),NOSPLIT,$0 + MOVD sig+0(FP), R3 + MOVD new+8(FP), R4 + MOVD old+16(FP), R5 + MOVD _cgo_sigaction(SB), R12 + MOVD R12, CTR // R12 should contain the function address + MOVD R1, R15 // Save R1 + MOVD R2, 24(R1) // Save R2 + SUB $48, R1 // reserve 32 (frame) + 16 bytes for sp-8 where fp may be saved. + RLDICR $0, R1, $59, R1 // Align to 16 bytes for C code + BL (CTR) + XOR R0, R0, R0 // Clear R0 as Go expects + MOVD R15, R1 // Restore R1 + MOVD 24(R1), R2 // Restore R2 + MOVW R3, ret+24(FP) // Return result + RET +#endif + TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 MOVW sig+8(FP), R3 MOVD info+16(FP), R4 @@ -351,15 +371,97 @@ TEXT runtime·sigreturn(SB),NOSPLIT,$0-0 #ifdef GOARCH_ppc64le // ppc64le doesn't need function descriptors -TEXT runtime·sigtramp(SB),NOSPLIT,$64 +// Save callee-save registers in the case of signal forwarding. +// Same as on ARM64 https://golang.org/issue/31827 . +TEXT runtime·sigtramp(SB),NOSPLIT|NOFRAME,$0 #else // function descriptor for the real sigtramp TEXT runtime·sigtramp(SB),NOSPLIT|NOFRAME,$0 DWORD $sigtramp<>(SB) DWORD $0 DWORD $0 -TEXT sigtramp<>(SB),NOSPLIT,$64 +TEXT sigtramp<>(SB),NOSPLIT|NOFRAME,$0 #endif + // Start with standard C stack frame layout and linkage. + MOVD LR, R0 + MOVD R0, 16(R1) // Save LR in caller's frame. + MOVW CR, R0 // Save CR in caller's frame + MOVD R0, 8(R1) + // The stack must be acquired here and not + // in the automatic way based on stack size + // since that sequence clobbers R31 before it + // gets saved. + // We are being ultra safe here in saving the + // Vregs. The case where they might need to + // be saved is very unlikely. + MOVDU R1, -544(R1) + MOVD R14, 64(R1) + MOVD R15, 72(R1) + MOVD R16, 80(R1) + MOVD R17, 88(R1) + MOVD R18, 96(R1) + MOVD R19, 104(R1) + MOVD R20, 112(R1) + MOVD R21, 120(R1) + MOVD R22, 128(R1) + MOVD R23, 136(R1) + MOVD R24, 144(R1) + MOVD R25, 152(R1) + MOVD R26, 160(R1) + MOVD R27, 168(R1) + MOVD R28, 176(R1) + MOVD R29, 184(R1) + MOVD g, 192(R1) // R30 + MOVD R31, 200(R1) + FMOVD F14, 208(R1) + FMOVD F15, 216(R1) + FMOVD F16, 224(R1) + FMOVD F17, 232(R1) + FMOVD F18, 240(R1) + FMOVD F19, 248(R1) + FMOVD F20, 256(R1) + FMOVD F21, 264(R1) + FMOVD F22, 272(R1) + FMOVD F23, 280(R1) + FMOVD F24, 288(R1) + FMOVD F25, 296(R1) + FMOVD F26, 304(R1) + FMOVD F27, 312(R1) + FMOVD F28, 320(R1) + FMOVD F29, 328(R1) + FMOVD F30, 336(R1) + FMOVD F31, 344(R1) + // Save V regs + // STXVD2X and LXVD2X used since + // we aren't sure of alignment. + // Endianness doesn't matter + // if we are just loading and + // storing values. + MOVD $352, R7 // V20 + STXVD2X VS52, (R7)(R1) + ADD $16, R7 // V21 368 + STXVD2X VS53, (R7)(R1) + ADD $16, R7 // V22 384 + STXVD2X VS54, (R7)(R1) + ADD $16, R7 // V23 400 + STXVD2X VS55, (R7)(R1) + ADD $16, R7 // V24 416 + STXVD2X VS56, (R7)(R1) + ADD $16, R7 // V25 432 + STXVD2X VS57, (R7)(R1) + ADD $16, R7 // V26 448 + STXVD2X VS58, (R7)(R1) + ADD $16, R7 // V27 464 + STXVD2X VS59, (R7)(R1) + ADD $16, R7 // V28 480 + STXVD2X VS60, (R7)(R1) + ADD $16, R7 // V29 496 + STXVD2X VS61, (R7)(R1) + ADD $16, R7 // V30 512 + STXVD2X VS62, (R7)(R1) + ADD $16, R7 // V31 528 + STXVD2X VS63, (R7)(R1) + // initialize essential registers (just in case) BL runtime·reginit(SB) @@ -376,7 +478,74 @@ TEXT sigtramp<>(SB),NOSPLIT,$64 MOVD $runtime·sigtrampgo(SB), R12 MOVD R12, CTR BL (CTR) - MOVD 24(R1), R2 + MOVD 24(R1), R2 // Should this be here? Where is it saved? + // Starts at 64; FIXED_FRAME is 32 + MOVD 64(R1), R14 + MOVD 72(R1), R15 + MOVD 80(R1), R16 + MOVD 88(R1), R17 + MOVD 96(R1), R18 + MOVD 104(R1), R19 + MOVD 112(R1), R20 + MOVD 120(R1), R21 + MOVD 128(R1), R22 + MOVD 136(R1), R23 + MOVD 144(R1), R24 + MOVD 152(R1), R25 + MOVD 160(R1), R26 + MOVD 168(R1), R27 + MOVD 176(R1), R28 + MOVD 184(R1), R29 + MOVD 192(R1), g // R30 + MOVD 200(R1), R31 + FMOVD 208(R1), F14 + FMOVD 216(R1), F15 + FMOVD 224(R1), F16 + FMOVD 232(R1), F17 + FMOVD 240(R1), F18 + FMOVD 248(R1), F19 + FMOVD 256(R1), F20 + FMOVD 264(R1), F21 + FMOVD 272(R1), F22 + FMOVD 280(R1), F23 + FMOVD 288(R1), F24 + FMOVD 292(R1), F25 + FMOVD 300(R1), F26 + FMOVD 308(R1), F27 + FMOVD 316(R1), F28 + FMOVD 328(R1), F29 + FMOVD 336(R1), F30 + FMOVD 344(R1), F31 + MOVD $352, R7 + LXVD2X (R7)(R1), VS52 + ADD $16, R7 // 368 V21 + LXVD2X (R7)(R1), VS53 + ADD $16, R7 // 384 V22 + LXVD2X (R7)(R1), VS54 + ADD $16, R7 // 400 V23 + LXVD2X (R7)(R1), VS55 + ADD $16, R7 // 416 V24 + LXVD2X (R7)(R1), VS56 + ADD $16, R7 // 432 V25 + LXVD2X (R7)(R1), VS57 + ADD $16, R7 // 448 V26 + LXVD2X (R7)(R1), VS58 + ADD $16, R8 // 464 V27 + LXVD2X (R7)(R1), VS59 + ADD $16, R7 // 480 V28 + LXVD2X (R7)(R1), VS60 + ADD $16, R7 // 496 V29 + LXVD2X (R7)(R1), VS61 + ADD $16, R7 // 512 V30 + LXVD2X (R7)(R1), VS62 + ADD $16, R7 // 528 V31 + LXVD2X (R7)(R1), VS63 + ADD $544, R1 + MOVD 8(R1), R0 + MOVFL R0, $0xff + MOVD 16(R1), R0 + MOVD R0, LR + RET #ifdef GOARCH_ppc64le @@ -406,6 +575,7 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT|NOFRAME,$0 // Figure out if we are currently in a cgo call. // If not, just do usual sigtramp. + // compared to ARM64 and others. CMP $0, g BEQ sigtrampnog // g == nil MOVD g_m(g), R6