mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Enable the use of compressed instructions on riscv64 by reducing the PC quantum to two bytes and reducing the minimum instruction length to two bytes. Change gostartcall on riscv64 to land at two times the PC quantum into goexit, so that we retain four byte alignment and revise the NOP instructions in goexit to ensure that they are never compressed. Additionally, adjust PCALIGN so that it correctly handles two byte offsets. Fixes #47560 Updates #71105 Cq-Include-Trybots: luci.golang.try:gotip-linux-riscv64 Change-Id: I4329a8fbfcb4de636aadaeadabb826bc22698640 Reviewed-on: https://go-review.googlesource.com/c/go/+/523477 Reviewed-by: Junyang Shao <shaojunyang@google.com> Reviewed-by: Mark Freeman <markfreeman@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Mark Ryan <markdryan@rivosinc.com>
287 lines
6.4 KiB
Go
287 lines
6.4 KiB
Go
// Copyright 2016 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.
|
|
|
|
package sys
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"internal/goarch"
|
|
)
|
|
|
|
// TODO: just use goarch.ArchFamilyType directly
|
|
type ArchFamily = goarch.ArchFamilyType
|
|
|
|
const (
|
|
AMD64 = goarch.AMD64
|
|
ARM = goarch.ARM
|
|
ARM64 = goarch.ARM64
|
|
I386 = goarch.I386
|
|
Loong64 = goarch.LOONG64
|
|
MIPS = goarch.MIPS
|
|
MIPS64 = goarch.MIPS64
|
|
PPC64 = goarch.PPC64
|
|
RISCV64 = goarch.RISCV64
|
|
S390X = goarch.S390X
|
|
Wasm = goarch.WASM
|
|
)
|
|
|
|
// Arch represents an individual architecture.
|
|
type Arch struct {
|
|
Name string
|
|
Family ArchFamily
|
|
|
|
ByteOrder binary.ByteOrder
|
|
|
|
// PtrSize is the size in bytes of pointers and the
|
|
// predeclared "int", "uint", and "uintptr" types.
|
|
PtrSize int
|
|
|
|
// RegSize is the size in bytes of general purpose registers.
|
|
RegSize int
|
|
|
|
// MinLC is the minimum length of an instruction code.
|
|
MinLC int
|
|
|
|
// Alignment is maximum alignment required by the architecture
|
|
// for any (compiler-generated) load or store instruction.
|
|
// Loads or stores smaller than Alignment must be naturally aligned.
|
|
// Loads or stores larger than Alignment need only be Alignment-aligned.
|
|
Alignment int8
|
|
|
|
// CanMergeLoads reports whether the backend optimization passes
|
|
// can combine adjacent loads into a single larger, possibly unaligned, load.
|
|
// Note that currently the optimizations must be able to handle little endian byte order.
|
|
CanMergeLoads bool
|
|
|
|
// CanJumpTable reports whether the backend can handle
|
|
// compiling a jump table.
|
|
CanJumpTable bool
|
|
|
|
// HasLR indicates that this architecture uses a link register
|
|
// for calls.
|
|
HasLR bool
|
|
|
|
// FixedFrameSize is the smallest possible offset from the
|
|
// hardware stack pointer to a local variable on the stack.
|
|
// Architectures that use a link register save its value on
|
|
// the stack in the function prologue and so always have a
|
|
// pointer between the hardware stack pointer and the local
|
|
// variable area.
|
|
FixedFrameSize int64
|
|
}
|
|
|
|
// InFamily reports whether a is a member of any of the specified
|
|
// architecture families.
|
|
func (a *Arch) InFamily(xs ...ArchFamily) bool {
|
|
for _, x := range xs {
|
|
if a.Family == x {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
var Arch386 = &Arch{
|
|
Name: "386",
|
|
Family: I386,
|
|
ByteOrder: binary.LittleEndian,
|
|
PtrSize: 4,
|
|
RegSize: 4,
|
|
MinLC: 1,
|
|
Alignment: 1,
|
|
CanMergeLoads: true,
|
|
HasLR: false,
|
|
FixedFrameSize: 0,
|
|
}
|
|
|
|
var ArchAMD64 = &Arch{
|
|
Name: "amd64",
|
|
Family: AMD64,
|
|
ByteOrder: binary.LittleEndian,
|
|
PtrSize: 8,
|
|
RegSize: 8,
|
|
MinLC: 1,
|
|
Alignment: 1,
|
|
CanMergeLoads: true,
|
|
CanJumpTable: true,
|
|
HasLR: false,
|
|
FixedFrameSize: 0,
|
|
}
|
|
|
|
var ArchARM = &Arch{
|
|
Name: "arm",
|
|
Family: ARM,
|
|
ByteOrder: binary.LittleEndian,
|
|
PtrSize: 4,
|
|
RegSize: 4,
|
|
MinLC: 4,
|
|
Alignment: 4, // TODO: just for arm5?
|
|
CanMergeLoads: false,
|
|
HasLR: true,
|
|
FixedFrameSize: 4, // LR
|
|
}
|
|
|
|
var ArchARM64 = &Arch{
|
|
Name: "arm64",
|
|
Family: ARM64,
|
|
ByteOrder: binary.LittleEndian,
|
|
PtrSize: 8,
|
|
RegSize: 8,
|
|
MinLC: 4,
|
|
Alignment: 1,
|
|
CanMergeLoads: true,
|
|
CanJumpTable: true,
|
|
HasLR: true,
|
|
FixedFrameSize: 8, // LR
|
|
}
|
|
|
|
var ArchLoong64 = &Arch{
|
|
Name: "loong64",
|
|
Family: Loong64,
|
|
ByteOrder: binary.LittleEndian,
|
|
PtrSize: 8,
|
|
RegSize: 8,
|
|
MinLC: 4,
|
|
Alignment: 8, // Unaligned accesses are not guaranteed to be fast
|
|
CanMergeLoads: true,
|
|
CanJumpTable: true,
|
|
HasLR: true,
|
|
FixedFrameSize: 8, // LR
|
|
}
|
|
|
|
var ArchMIPS = &Arch{
|
|
Name: "mips",
|
|
Family: MIPS,
|
|
ByteOrder: binary.BigEndian,
|
|
PtrSize: 4,
|
|
RegSize: 4,
|
|
MinLC: 4,
|
|
Alignment: 4,
|
|
CanMergeLoads: false,
|
|
HasLR: true,
|
|
FixedFrameSize: 4, // LR
|
|
}
|
|
|
|
var ArchMIPSLE = &Arch{
|
|
Name: "mipsle",
|
|
Family: MIPS,
|
|
ByteOrder: binary.LittleEndian,
|
|
PtrSize: 4,
|
|
RegSize: 4,
|
|
MinLC: 4,
|
|
Alignment: 4,
|
|
CanMergeLoads: false,
|
|
HasLR: true,
|
|
FixedFrameSize: 4, // LR
|
|
}
|
|
|
|
var ArchMIPS64 = &Arch{
|
|
Name: "mips64",
|
|
Family: MIPS64,
|
|
ByteOrder: binary.BigEndian,
|
|
PtrSize: 8,
|
|
RegSize: 8,
|
|
MinLC: 4,
|
|
Alignment: 8,
|
|
CanMergeLoads: false,
|
|
HasLR: true,
|
|
FixedFrameSize: 8, // LR
|
|
}
|
|
|
|
var ArchMIPS64LE = &Arch{
|
|
Name: "mips64le",
|
|
Family: MIPS64,
|
|
ByteOrder: binary.LittleEndian,
|
|
PtrSize: 8,
|
|
RegSize: 8,
|
|
MinLC: 4,
|
|
Alignment: 8,
|
|
CanMergeLoads: false,
|
|
HasLR: true,
|
|
FixedFrameSize: 8, // LR
|
|
}
|
|
|
|
var ArchPPC64 = &Arch{
|
|
Name: "ppc64",
|
|
Family: PPC64,
|
|
ByteOrder: binary.BigEndian,
|
|
PtrSize: 8,
|
|
RegSize: 8,
|
|
MinLC: 4,
|
|
Alignment: 1,
|
|
CanMergeLoads: true,
|
|
HasLR: true,
|
|
// PIC code on ppc64le requires 32 bytes of stack, and it's
|
|
// easier to just use that much stack always.
|
|
FixedFrameSize: 4 * 8,
|
|
}
|
|
|
|
var ArchPPC64LE = &Arch{
|
|
Name: "ppc64le",
|
|
Family: PPC64,
|
|
ByteOrder: binary.LittleEndian,
|
|
PtrSize: 8,
|
|
RegSize: 8,
|
|
MinLC: 4,
|
|
Alignment: 1,
|
|
CanMergeLoads: true,
|
|
HasLR: true,
|
|
FixedFrameSize: 4 * 8,
|
|
}
|
|
|
|
var ArchRISCV64 = &Arch{
|
|
Name: "riscv64",
|
|
Family: RISCV64,
|
|
ByteOrder: binary.LittleEndian,
|
|
PtrSize: 8,
|
|
RegSize: 8,
|
|
MinLC: 2,
|
|
Alignment: 8, // riscv unaligned loads work, but are really slow (trap + simulated by OS)
|
|
CanMergeLoads: false,
|
|
HasLR: true,
|
|
FixedFrameSize: 8, // LR
|
|
}
|
|
|
|
var ArchS390X = &Arch{
|
|
Name: "s390x",
|
|
Family: S390X,
|
|
ByteOrder: binary.BigEndian,
|
|
PtrSize: 8,
|
|
RegSize: 8,
|
|
MinLC: 2,
|
|
Alignment: 1,
|
|
CanMergeLoads: true,
|
|
HasLR: true,
|
|
FixedFrameSize: 8, // LR
|
|
}
|
|
|
|
var ArchWasm = &Arch{
|
|
Name: "wasm",
|
|
Family: Wasm,
|
|
ByteOrder: binary.LittleEndian,
|
|
PtrSize: 8,
|
|
RegSize: 8,
|
|
MinLC: 1,
|
|
Alignment: 1,
|
|
CanMergeLoads: false,
|
|
HasLR: false,
|
|
FixedFrameSize: 0,
|
|
}
|
|
|
|
var Archs = [...]*Arch{
|
|
Arch386,
|
|
ArchAMD64,
|
|
ArchARM,
|
|
ArchARM64,
|
|
ArchLoong64,
|
|
ArchMIPS,
|
|
ArchMIPSLE,
|
|
ArchMIPS64,
|
|
ArchMIPS64LE,
|
|
ArchPPC64,
|
|
ArchPPC64LE,
|
|
ArchRISCV64,
|
|
ArchS390X,
|
|
ArchWasm,
|
|
}
|