cmd/internal/obj, cmd/compile: refactor encoding arm64 RegisterArrangement

Refactor cmd/internal/obj/arm64 and cmd/compile to use common helper
function arm64.RegisterArrangement.

Change-Id: I61201c6ff31cf146e5db33294319a927509b931a
Reviewed-on: https://go-review.googlesource.com/c/go/+/714321
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: Keith Randall <khr@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@golang.org>
Auto-Submit: Keith Randall <khr@golang.org>
This commit is contained in:
Alexander Musman 2025-10-23 19:53:26 +03:00 committed by Gopher Robot
parent 5e45c1df65
commit 85f838f46c
2 changed files with 102 additions and 81 deletions

View file

@ -162,6 +162,38 @@ func genIndexedOperand(op ssa.Op, base, idx int16) obj.Addr {
return mop
}
// simdRegArng encodes ssa value's register with specified simd arrangement
func simdRegArng(reg int16, arng int16) int16 {
if reg < arm64.REG_F0 || arm64.REG_F31 < reg {
base.Fatalf("expected fp register: r%d", reg)
}
var err error
if reg, err = arm64.RegisterArrangement(reg, arng, false); err != nil {
base.Fatalf("bad simd register arrangement: %v", err)
}
return reg
}
// simdV11 generates element-wise unary vector operations, e.g. VCNT V1.B8, V0.B8
func simdV11(s *ssagen.State, v *ssa.Value, arrangement int16) *obj.Prog {
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = simdRegArng(v.Args[0].Reg(), arrangement)
p.To.Type = obj.TYPE_REG
p.To.Reg = simdRegArng(v.Reg(), arrangement)
return p
}
// simdV11Scalar generates vector-to-scalar reduction operations, e.g. VUADDLV V1.B8, V0
func simdV11Scalar(s *ssagen.State, v *ssa.Value, arrangement int16) *obj.Prog {
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = simdRegArng(v.Args[0].Reg(), arrangement)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() - arm64.REG_F0 + arm64.REG_V0
return p
}
func ssaGenValue(s *ssagen.State, v *ssa.Value) {
switch v.Op {
case ssa.OpCopy, ssa.OpARM64MOVDreg:
@ -1018,17 +1050,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
case ssa.OpARM64LoweredRound32F, ssa.OpARM64LoweredRound64F:
// input is already rounded
case ssa.OpARM64VCNT:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = (v.Args[0].Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5)
p.To.Type = obj.TYPE_REG
p.To.Reg = (v.Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5)
simdV11(s, v, arm64.ARNG_8B)
case ssa.OpARM64VUADDLV:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = (v.Args[0].Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() - arm64.REG_F0 + arm64.REG_V0
simdV11Scalar(s, v, arm64.ARNG_8B)
case ssa.OpARM64CSEL, ssa.OpARM64CSEL0:
r1 := int16(arm64.REGZERO)
if v.Op != ssa.OpARM64CSEL0 {

View file

@ -8555,85 +8555,82 @@ func EncodeRegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount,
}
a.Reg = REG_PARNGZM + (reg & 31) + int16((arng&15)<<5)
} else if reg <= REG_V31 && reg >= REG_V0 {
switch ext {
case "B8":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = REG_ARNG + (reg & 31) + ((ARNG_8B & 15) << 5)
case "B16":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = REG_ARNG + (reg & 31) + ((ARNG_16B & 15) << 5)
case "H4":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = REG_ARNG + (reg & 31) + ((ARNG_4H & 15) << 5)
case "H8":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = REG_ARNG + (reg & 31) + ((ARNG_8H & 15) << 5)
case "S2":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = REG_ARNG + (reg & 31) + ((ARNG_2S & 15) << 5)
case "S4":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = REG_ARNG + (reg & 31) + ((ARNG_4S & 15) << 5)
case "D1":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = REG_ARNG + (reg & 31) + ((ARNG_1D & 15) << 5)
case "D2":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = REG_ARNG + (reg & 31) + ((ARNG_2D & 15) << 5)
case "Q1":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = REG_ARNG + (reg & 31) + ((ARNG_1Q & 15) << 5)
case "B":
if !isIndex {
return nil
}
a.Reg = REG_ELEM + (reg & 31) + ((ARNG_B & 15) << 5)
a.Index = num
case "H":
if !isIndex {
return nil
}
a.Reg = REG_ELEM + (reg & 31) + ((ARNG_H & 15) << 5)
a.Index = num
case "S":
if !isIndex {
return nil
}
a.Reg = REG_ELEM + (reg & 31) + ((ARNG_S & 15) << 5)
a.Index = num
case "D":
if !isIndex {
return nil
}
a.Reg = REG_ELEM + (reg & 31) + ((ARNG_D & 15) << 5)
a.Index = num
default:
arng, elem := readArrangement(ext)
if arng == -1 {
return errors.New("unsupported simd register extension type: " + ext)
}
if elem && !isIndex {
return nil
}
var err error
if reg, err = RegisterArrangement(reg, arng, isIndex); err != nil {
return err
}
a.Reg = reg
if isIndex {
a.Index = num
}
} else {
return errors.New("invalid register and extension combination")
}
return nil
}
// readArrangement returns arrangement constant (or -1 for unknown arrangement)
// and a boolean flag specifying whether it refers to a vector element.
func readArrangement(name string) (arng int16, elem bool) {
switch name {
case "B8":
return ARNG_8B, false
case "B16":
return ARNG_16B, false
case "H4":
return ARNG_4H, false
case "H8":
return ARNG_8H, false
case "S2":
return ARNG_2S, false
case "S4":
return ARNG_4S, false
case "D1":
return ARNG_1D, false
case "D2":
return ARNG_2D, false
case "B":
return ARNG_B, true
case "H":
return ARNG_H, true
case "S":
return ARNG_S, true
case "D":
return ARNG_D, true
case "Q1":
return ARNG_1Q, false
default:
return -1, false
}
}
// RegisterArrangement encodes specified simd register number and arrangement.
func RegisterArrangement(reg int16, arng int16, isIndex bool) (int16, error) {
arng &= 15
arrangement := arng << 5
switch arng {
case ARNG_B, ARNG_H, ARNG_S, ARNG_D:
if !isIndex {
return reg, nil
}
return REG_ELEM + (reg & 31) + arrangement, nil
case ARNG_16B, ARNG_8H, ARNG_4S, ARNG_2D,
ARNG_8B, ARNG_4H, ARNG_2S, ARNG_1D, ARNG_1Q:
if isIndex {
return 0, errors.New("invalid register extension")
}
return REG_ARNG + (reg & 31) + arrangement, nil
}
return 0, errors.New("unsupported simd register arrangement: " + fmt.Sprint(arng))
}
// RegisterListOffset generates offset encoding according to AArch64 specification.
func RegisterListOffset(firstReg, regCnt int, arrangement int64, scale int16) (int64, error) {
offset := int64(firstReg)