From 2c5499b57cf4a68ebc8decce90d3eb1e281c31a9 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 28 Aug 2020 16:05:56 +0100 Subject: [PATCH] libgo: add 32-bit RISC-V (RV32) support Add support for the 32-bit RISC-V (RV32) ISA matching the 64-bit RISC-V (RV64) port except for async preemption added as a stub only. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/251179 --- gcc/go/gofrontend/MERGE | 2 +- libgo/configure | 17 +++++++- libgo/configure.ac | 10 ++++- libgo/go/cmd/cgo/main.go | 2 + .../testdata/script/link_syso_issue33139.txt | 3 +- libgo/go/cmd/internal/sys/arch.go | 11 +++++ libgo/go/debug/elf/file.go | 43 +++++++++++++++++++ libgo/go/go/types/sizes.go | 4 +- libgo/go/golang.org/x/sys/cpu/cpu_riscv.go | 7 +++ .../go/analysis/passes/asmdecl/asmdecl.go | 2 + .../go/internal/bytealg/indexbyte_generic.go | 2 +- libgo/go/internal/bytealg/indexbyte_native.go | 2 +- .../syscall/unix/sysnum_linux_generic.go | 2 +- libgo/go/runtime/gcinfo_test.go | 2 +- libgo/go/runtime/hash32.go | 2 +- libgo/go/runtime/lfstack_32bit.go | 2 +- libgo/go/runtime/mkpreempt.go | 6 +++ libgo/go/runtime/mpagealloc_32bit.go | 2 +- libgo/go/syscall/endian_little.go | 2 +- libgo/match.sh | 4 +- .../cgo/testcshared/testdata/libgo2/dup2.go | 2 +- .../cgo/testcshared/testdata/libgo2/dup3.go | 2 +- libgo/testsuite/gotest | 4 +- 23 files changed, 114 insertions(+), 21 deletions(-) create mode 100644 libgo/go/golang.org/x/sys/cpu/cpu_riscv.go diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 314ffd2efab..8d9fda54619 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -9e55baf44ab63ba06af0b57038e7b3aab8216222 +c9c084bce713e258721e12041a351ec8ad33ad17 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/configure b/libgo/configure index 7be95718962..641d060ffac 100755 --- a/libgo/configure +++ b/libgo/configure @@ -14226,8 +14226,21 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ;; - riscv64-*-*) - GOARCH=riscv64 + riscv*-*-*) + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if __riscv_xlen == 64 +#error 64-bit +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + GOARCH=riscv +else + GOARCH=riscv64 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ;; s390*-*-*) cat confdefs.h - <<_ACEOF >conftest.$ac_ext diff --git a/libgo/configure.ac b/libgo/configure.ac index abc58b87b53..f15f8d830bb 100644 --- a/libgo/configure.ac +++ b/libgo/configure.ac @@ -342,8 +342,14 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([ [GOARCH=ppc64le], [GOARCH=ppc64])]) ;; - riscv64-*-*) - GOARCH=riscv64 + riscv*-*-*) + AC_COMPILE_IFELSE([AC_LANG_SOURCE([ +#if __riscv_xlen == 64 +#error 64-bit +#endif +])], +[GOARCH=riscv], +[GOARCH=riscv64]) ;; s390*-*-*) AC_COMPILE_IFELSE([AC_LANG_SOURCE([ diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go index 80f35681d75..6de6d69ce6c 100644 --- a/libgo/go/cmd/cgo/main.go +++ b/libgo/go/cmd/cgo/main.go @@ -184,6 +184,7 @@ var ptrSizeMap = map[string]int64{ "ppc": 4, "ppc64": 8, "ppc64le": 8, + "riscv": 4, "riscv64": 8, "s390": 4, "s390x": 8, @@ -210,6 +211,7 @@ var intSizeMap = map[string]int64{ "ppc": 4, "ppc64": 8, "ppc64le": 8, + "riscv": 4, "riscv64": 8, "s390": 4, "s390x": 8, diff --git a/libgo/go/cmd/go/testdata/script/link_syso_issue33139.txt b/libgo/go/cmd/go/testdata/script/link_syso_issue33139.txt index 46b0ef4200e..3030ee924ff 100644 --- a/libgo/go/cmd/go/testdata/script/link_syso_issue33139.txt +++ b/libgo/go/cmd/go/testdata/script/link_syso_issue33139.txt @@ -8,8 +8,9 @@ # See: https://github.com/golang/go/issues/8912 [linux] [ppc64] skip -# External linking is not supported on linux/riscv64. +# External linking is not supported on linux/riscv, linux/riscv64. # See: https://github.com/golang/go/issues/36739 +[linux] [riscv] skip [linux] [riscv64] skip cc -c -o syso/objTestImpl.syso syso/src/objTestImpl.c diff --git a/libgo/go/cmd/internal/sys/arch.go b/libgo/go/cmd/internal/sys/arch.go index e8687363def..60a3b3c8ecd 100644 --- a/libgo/go/cmd/internal/sys/arch.go +++ b/libgo/go/cmd/internal/sys/arch.go @@ -19,6 +19,7 @@ const ( MIPS MIPS64 PPC64 + RISCV RISCV64 S390X Wasm @@ -143,6 +144,15 @@ var ArchPPC64LE = &Arch{ MinLC: 4, } +var ArchRISCV = &Arch{ + Name: "riscv", + Family: RISCV, + ByteOrder: binary.LittleEndian, + PtrSize: 4, + RegSize: 4, + MinLC: 4, +} + var ArchRISCV64 = &Arch{ Name: "riscv64", Family: RISCV64, @@ -181,6 +191,7 @@ var Archs = [...]*Arch{ ArchMIPS64LE, ArchPPC64, ArchPPC64LE, + ArchRISCV, ArchRISCV64, ArchS390X, ArchWasm, diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go index b9a8b1e0cbb..48178d480d7 100644 --- a/libgo/go/debug/elf/file.go +++ b/libgo/go/debug/elf/file.go @@ -617,6 +617,8 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error { return f.applyRelocationsMIPS(dst, rels) case f.Class == ELFCLASS64 && f.Machine == EM_MIPS: return f.applyRelocationsMIPS64(dst, rels) + case f.Class == ELFCLASS32 && f.Machine == EM_RISCV: + return f.applyRelocationsRISCV(dst, rels) case f.Class == ELFCLASS64 && f.Machine == EM_RISCV: return f.applyRelocationsRISCV64(dst, rels) case f.Class == ELFCLASS64 && f.Machine == EM_S390: @@ -1008,6 +1010,47 @@ func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error { return nil } +func (f *File) applyRelocationsRISCV(dst []byte, rels []byte) error { + // 12 is the size of Rela32. + if len(rels)%12 != 0 { + return errors.New("length of relocation section is not a multiple of 12") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 8 + t := R_RISCV(rela.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + needed, val := relocSymbolTargetOK(sym) + if !needed { + continue + } + + switch t { + case R_RISCV_32: + if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 { + continue + } + val32 := uint32(val) + uint32(rela.Addend) + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val32) + } + } + + return nil +} + func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error { // 24 is the size of Rela64. if len(rels)%24 != 0 { diff --git a/libgo/go/go/types/sizes.go b/libgo/go/go/types/sizes.go index 6ab6157b82d..4787b242cc0 100644 --- a/libgo/go/go/types/sizes.go +++ b/libgo/go/go/types/sizes.go @@ -167,6 +167,7 @@ var gcArchSizes = map[string]*StdSizes{ "mips64le": {8, 8}, "ppc64": {8, 8}, "ppc64le": {8, 8}, + "riscv": {4, 4}, "riscv64": {8, 8}, "s390x": {8, 8}, "sparc64": {8, 8}, @@ -180,7 +181,8 @@ var gcArchSizes = map[string]*StdSizes{ // // Supported architectures for compiler "gc": // "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle", -// "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "sparc64", "wasm". +// "mips64", "mips64le", "ppc64", "ppc64le", "riscv", "riscv64", +// "s390x", "sparc64", "wasm". func SizesFor(compiler, arch string) Sizes { var m map[string]*StdSizes switch compiler { diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_riscv.go b/libgo/go/golang.org/x/sys/cpu/cpu_riscv.go new file mode 100644 index 00000000000..891cb98b455 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/cpu_riscv.go @@ -0,0 +1,7 @@ +// Copyright 2020 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. + +// +build riscv + +package cpu diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go b/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go index e6bfe715391..0f521503ac6 100644 --- a/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go +++ b/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go @@ -87,6 +87,7 @@ var ( asmArchMips64LE = asmArch{name: "mips64le", bigEndian: false, stack: "R29", lr: true} asmArchPpc64 = asmArch{name: "ppc64", bigEndian: true, stack: "R1", lr: true} asmArchPpc64LE = asmArch{name: "ppc64le", bigEndian: false, stack: "R1", lr: true} + asmArchRISCV = asmArch{name: "riscv", bigEndian: false, stack: "SP", lr: true} asmArchRISCV64 = asmArch{name: "riscv64", bigEndian: false, stack: "SP", lr: true} asmArchS390X = asmArch{name: "s390x", bigEndian: true, stack: "R15", lr: true} asmArchWasm = asmArch{name: "wasm", bigEndian: false, stack: "SP", lr: false} @@ -102,6 +103,7 @@ var ( &asmArchMips64LE, &asmArchPpc64, &asmArchPpc64LE, + &asmArchRISCV, &asmArchRISCV64, &asmArchS390X, &asmArchWasm, diff --git a/libgo/go/internal/bytealg/indexbyte_generic.go b/libgo/go/internal/bytealg/indexbyte_generic.go index a863d814b6b..46325dd7f07 100644 --- a/libgo/go/internal/bytealg/indexbyte_generic.go +++ b/libgo/go/internal/bytealg/indexbyte_generic.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build ignore_for_gccgo -// +build !386,!amd64,!s390x,!arm,!arm64,!ppc64,!ppc64le,!mips,!mipsle,!mips64,!mips64le,!riscv64,!wasm +// +build !386,!amd64,!s390x,!arm,!arm64,!ppc64,!ppc64le,!mips,!mipsle,!mips64,!mips64le,!riscv,!riscv64,!wasm package bytealg diff --git a/libgo/go/internal/bytealg/indexbyte_native.go b/libgo/go/internal/bytealg/indexbyte_native.go index 20da788fb86..c427e669bbd 100644 --- a/libgo/go/internal/bytealg/indexbyte_native.go +++ b/libgo/go/internal/bytealg/indexbyte_native.go @@ -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 386 amd64 s390x arm arm64 ppc64 ppc64le mips mipsle mips64 mips64le riscv64 wasm +// -build 386 amd64 s390x arm arm64 ppc64 ppc64le mips mipsle mips64 mips64le riscv riscv64 wasm package bytealg diff --git a/libgo/go/internal/syscall/unix/sysnum_linux_generic.go b/libgo/go/internal/syscall/unix/sysnum_linux_generic.go index 3e00703679a..3d34fdb73e3 100644 --- a/libgo/go/internal/syscall/unix/sysnum_linux_generic.go +++ b/libgo/go/internal/syscall/unix/sysnum_linux_generic.go @@ -9,7 +9,7 @@ package unix // This file is named "generic" because at a certain point Linux started // standardizing on system call numbers across architectures. So far this -// means only arm64, nios2 and riscv use the standard numbers. +// means only arm64, nios2, riscv and riscv64 use the standard numbers. const ( getrandomTrap uintptr = 278 diff --git a/libgo/go/runtime/gcinfo_test.go b/libgo/go/runtime/gcinfo_test.go index ddbe5dd5fea..c26f411153f 100644 --- a/libgo/go/runtime/gcinfo_test.go +++ b/libgo/go/runtime/gcinfo_test.go @@ -157,7 +157,7 @@ type BigStruct struct { func infoBigStruct() []byte { switch runtime.GOARCH { - case "386", "arm", "mips", "mipsle": + case "386", "arm", "mips", "mipsle", "riscv": return []byte{ typePointer, // q *int typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte diff --git a/libgo/go/runtime/hash32.go b/libgo/go/runtime/hash32.go index fba6bc354b1..89efc1cde5c 100644 --- a/libgo/go/runtime/hash32.go +++ b/libgo/go/runtime/hash32.go @@ -6,7 +6,7 @@ // xxhash: https://code.google.com/p/xxhash/ // cityhash: https://code.google.com/p/cityhash/ -// +build 386 arm armbe m68k mips mipsle nios2 ppc s390 sh shbe sparc +// +build 386 arm armbe m68k mips mipsle nios2 ppc riscv s390 sh shbe sparc package runtime diff --git a/libgo/go/runtime/lfstack_32bit.go b/libgo/go/runtime/lfstack_32bit.go index 6da037e3f36..b3194dc7668 100644 --- a/libgo/go/runtime/lfstack_32bit.go +++ b/libgo/go/runtime/lfstack_32bit.go @@ -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 386 amd64p32 arm armbe m68k mips mipsle mips64p32 mips64p32le nios2 ppc s390 sh shbe sparc +// +build 386 amd64p32 arm armbe m68k mips mipsle mips64p32 mips64p32le nios2 ppc riscv s390 sh shbe sparc package runtime diff --git a/libgo/go/runtime/mkpreempt.go b/libgo/go/runtime/mkpreempt.go index 1fe77663b9c..268941d3532 100644 --- a/libgo/go/runtime/mkpreempt.go +++ b/libgo/go/runtime/mkpreempt.go @@ -83,6 +83,7 @@ var arches = map[string]func(){ "mips64x": func() { genMIPS(true) }, "mipsx": func() { genMIPS(false) }, "ppc64x": genPPC64, + "riscv": genRISCV, "riscv64": genRISCV64, "s390x": genS390X, "wasm": genWasm, @@ -501,6 +502,11 @@ func genPPC64() { p("JMP (CTR)") } +func genRISCV() { + p("// No async preemption on riscv - see issue 36711") + p("UNDEF") +} + func genRISCV64() { // X0 (zero), X1 (LR), X2 (SP), X4 (g), X31 (TMP) are special. var l = layout{sp: "X2", stack: 8} diff --git a/libgo/go/runtime/mpagealloc_32bit.go b/libgo/go/runtime/mpagealloc_32bit.go index d18970ca26c..249b5fea01b 100644 --- a/libgo/go/runtime/mpagealloc_32bit.go +++ b/libgo/go/runtime/mpagealloc_32bit.go @@ -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 386 arm mips mipsle wasm darwin,arm64 amd64p32 armbe m68k mips64p32 mips64p32le nios2 ppc s390 sh shbe sparc +// +build 386 arm mips mipsle wasm darwin,arm64 amd64p32 armbe m68k mips64p32 mips64p32le nios2 ppc riscv s390 sh shbe sparc // wasm is a treated as a 32-bit architecture for the purposes of the page // allocator, even though it has 64-bit pointers. This is because any wasm diff --git a/libgo/go/syscall/endian_little.go b/libgo/go/syscall/endian_little.go index 0cd2d7524c6..22cac17ef11 100644 --- a/libgo/go/syscall/endian_little.go +++ b/libgo/go/syscall/endian_little.go @@ -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 386 alpha amd64 amd64p32 arm arm64 ia64 mips64le mipsle mips64p32le nios2 ppc64le riscv64 sh wasm +// +build 386 alpha amd64 amd64p32 arm arm64 ia64 mips64le mipsle mips64p32le nios2 ppc64le riscv riscv64 sh wasm package syscall diff --git a/libgo/match.sh b/libgo/match.sh index cd35942f8bc..6f7b368f8bf 100755 --- a/libgo/match.sh +++ b/libgo/match.sh @@ -116,7 +116,7 @@ for f in $gofiles; do aix | android | darwin | dragonfly | freebsd | illumos | hurd | js | linux | nacl | netbsd | openbsd | plan9 | solaris | windows) tag1=nonmatchingtag ;; - 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | nios2 | ppc | ppc64 | ppc64le | riscv64 | s390 | s390x | sh | shbe | sparc | sparc64 | wasm) + 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | nios2 | ppc | ppc64 | ppc64le | riscv | riscv64 | s390 | s390x | sh | shbe | sparc | sparc64 | wasm) tag1=nonmatchingtag ;; esac @@ -128,7 +128,7 @@ for f in $gofiles; do aix | android | darwin | dragonfly | freebsd | hurd | illumos | js | linux | nacl | netbsd | openbsd | plan9 | solaris | windows) tag2=nonmatchingtag ;; - 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | nios2 | ppc | ppc64 | ppc64le | riscv64 | s390 | s390x | sh | shbe | sparc | sparc64 | wasm) + 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | nios2 | ppc | ppc64 | ppc64le | riscv | riscv64 | s390 | s390x | sh | shbe | sparc | sparc64 | wasm) tag2=nonmatchingtag ;; esac diff --git a/libgo/misc/cgo/testcshared/testdata/libgo2/dup2.go b/libgo/misc/cgo/testcshared/testdata/libgo2/dup2.go index d343aa54d9a..3b53e1ceea2 100644 --- a/libgo/misc/cgo/testcshared/testdata/libgo2/dup2.go +++ b/libgo/misc/cgo/testcshared/testdata/libgo2/dup2.go @@ -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 darwin dragonfly freebsd linux,!arm64,!riscv64 netbsd openbsd +// +build darwin dragonfly freebsd linux,!arm64,!riscv,!riscv64 netbsd openbsd package main diff --git a/libgo/misc/cgo/testcshared/testdata/libgo2/dup3.go b/libgo/misc/cgo/testcshared/testdata/libgo2/dup3.go index 459f0dc1968..79a37730c84 100644 --- a/libgo/misc/cgo/testcshared/testdata/libgo2/dup3.go +++ b/libgo/misc/cgo/testcshared/testdata/libgo2/dup3.go @@ -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,arm64 linux,riscv64 +// +build linux,arm64 linux,riscv,riscv64 package main diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest index eadafa1a7cd..5bb27ec1631 100755 --- a/libgo/testsuite/gotest +++ b/libgo/testsuite/gotest @@ -308,7 +308,7 @@ x) aix | android | darwin | dragonfly | freebsd | hurd | illumos | js | linux | nacl | netbsd | openbsd | plan9 | solaris | windows) tag1=nonmatchingtag ;; - 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | nios2 | ppc | ppc64 | ppc64le | riscv64 | s390 | s390x | sh | shbe | sparc | sparc64 | wasm) + 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | nios2 | ppc | ppc64 | ppc64le | riscv | riscv64 | s390 | s390x | sh | shbe | sparc | sparc64 | wasm) tag1=nonmatchingtag ;; esac @@ -320,7 +320,7 @@ x) aix | android | darwin | dragonfly | freebsd | hurd | illumos | js | linux | nacl | netbsd | openbsd | plan9 | solaris | windows) tag2=nonmatchingtag ;; - 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | nios2 | ppc | ppc64 | ppc64le | riscv64 | s390 | s390x | sh | shbe | sparc | sparc64 | wasm) + 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | ia64 | m68k | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | nios2 | ppc | ppc64 | ppc64le | riscv | riscv64 | s390 | s390x | sh | shbe | sparc | sparc64 | wasm) tag2=nonmatchingtag ;; esac -- 2.30.2