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.

Change-Id: I0aacceb7e85243cc0e422d55baf61e1b6185b998
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/251179
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Trust: Than McIntosh <thanm@google.com>
diff --git a/libgo/configure b/libgo/configure
index 7be9571..641d060 100755
--- a/libgo/configure
+++ b/libgo/configure
@@ -14226,8 +14226,21 @@
 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 abc58b8..f15f8d8 100644
--- a/libgo/configure.ac
+++ b/libgo/configure.ac
@@ -342,8 +342,14 @@
 [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 80f3568..6de6d69 100644
--- a/libgo/go/cmd/cgo/main.go
+++ b/libgo/go/cmd/cgo/main.go
@@ -184,6 +184,7 @@
 	"ppc":         4,
 	"ppc64":       8,
 	"ppc64le":     8,
+	"riscv":       4,
 	"riscv64":     8,
 	"s390":        4,
 	"s390x":       8,
@@ -210,6 +211,7 @@
 	"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 46b0ef4..3030ee9 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 e868736..60a3b3c 100644
--- a/libgo/go/cmd/internal/sys/arch.go
+++ b/libgo/go/cmd/internal/sys/arch.go
@@ -19,6 +19,7 @@
 	MIPS
 	MIPS64
 	PPC64
+	RISCV
 	RISCV64
 	S390X
 	Wasm
@@ -143,6 +144,15 @@
 	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 @@
 	ArchMIPS64LE,
 	ArchPPC64,
 	ArchPPC64LE,
+	ArchRISCV,
 	ArchRISCV64,
 	ArchS390X,
 	ArchWasm,
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
index b9a8b1e..48178d4 100644
--- a/libgo/go/debug/elf/file.go
+++ b/libgo/go/debug/elf/file.go
@@ -617,6 +617,8 @@
 		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 @@
 	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 6ab6157..4787b24 100644
--- a/libgo/go/go/types/sizes.go
+++ b/libgo/go/go/types/sizes.go
@@ -167,6 +167,7 @@
 	"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 @@
 //
 // 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 0000000..891cb98
--- /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 e6bfe71..0f52150 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 @@
 	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 @@
 		&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 a863d81..46325dd 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 20da788..c427e66 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 3e00703..3d34fdb 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 @@
 
 // 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 ddbe5dd..c26f411 100644
--- a/libgo/go/runtime/gcinfo_test.go
+++ b/libgo/go/runtime/gcinfo_test.go
@@ -157,7 +157,7 @@
 
 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 fba6bc3..89efc1c 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 6da037e..b3194dc 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 1fe7766..268941d 100644
--- a/libgo/go/runtime/mkpreempt.go
+++ b/libgo/go/runtime/mkpreempt.go
@@ -83,6 +83,7 @@
 	"mips64x": func() { genMIPS(true) },
 	"mipsx":   func() { genMIPS(false) },
 	"ppc64x":  genPPC64,
+	"riscv":   genRISCV,
 	"riscv64": genRISCV64,
 	"s390x":   genS390X,
 	"wasm":    genWasm,
@@ -501,6 +502,11 @@
 	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 d18970c..249b5fe 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 0cd2d75..22cac17 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 cd35942..6f7b368 100755
--- a/libgo/match.sh
+++ b/libgo/match.sh
@@ -116,7 +116,7 @@
 	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 @@
 	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 d343aa5..3b53e1c 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 459f0dc..79a3773 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 eadafa1..5bb27ec 100755
--- a/libgo/testsuite/gotest
+++ b/libgo/testsuite/gotest
@@ -308,7 +308,7 @@
 	    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 @@
 	    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