// Copyright 2025 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 main

import "fmt"

// ArchInfo contains all architecture-specific naming conventions.
type ArchInfo struct {
	Arch            string          // e.g., "amd64", "arm64"
	ArchUpper       string          // e.g., "AMD64", "ARM64"
	ObjArch         string          // e.g., "x86", "arm64" (for cmd/internal/obj/*)
	RegInfoKeys     []string        // RegInfo shapes that generate SSA lowering code (gen_simdssa.go)
	RegInfoSet      map[string]bool // Valid regInfo shapes (for gen_simdMachineOps.go)
	RegInfoParams   string          // Function parameter declaration for generated ops (simd[AMD64|ARM64]ops.go)
	GeneratedHeader string          // Header comment for generated files
	Arrangements    []string        // SIMD arrangement suffixes (e.g., "4S", "2D" for ARM64; nil for amd64)
}

var amd64RegInfoKeys = []string{
	"v11",
	"v21",
	"v2k",
	"v2kv",
	"v2kk",
	"vkv",
	"v31",
	"v3kv",
	"v11Imm8",
	"vkvImm8",
	"v21Imm8",
	"v2kImm8",
	"v2kkImm8",
	"v31ResultInArg0",
	"v3kvResultInArg0",
	"vfpv",
	"vfpkv",
	"vgpvImm8",
	"vgpvImm",
	"vgpImm8",
	"vgpImm",
	"v2kvImm8",
	"vkvload",
	"v21load",
	"v31loadResultInArg0",
	"v3kvloadResultInArg0",
	"v2kvload",
	"v2kload",
	"v11load",
	"v11loadImm8",
	"vkvloadImm8",
	"v21loadImm8",
	"v2kloadImm8",
	"v2kkloadImm8",
	"v2kvloadImm8",
	"v31ResultInArg0Imm8",
	"v31loadResultInArg0Imm8",
	"v21ResultInArg0",
	"v21ResultInArg0Imm8",
	"v31x0AtIn2ResultInArg0",
	"v2kvResultInArg0",
}

var arm64RegInfoKeys = []string{
	"v11",
	"v11Imm",
	"v11ImmIn1",
	"v11Scalar",
	"v11ScalarImmIn1",
	"v21",
	"v21Imm",
	"v31ResultInArg0",
	"vgpImmIn1",
	"vgpvResultInArg0ImmOutIn0",
	"vfpvResultInArg0ImmOutIn1",
	"v11Long",
	"v11Narrow",
	"v11ImmNarrow",
	"v11ImmLong",
	"v21Long",
	"v11Long2",
	"v21Narrow2",
	"v21ImmNarrow2",
	"v11ImmLong2",
	"v21Long2",
	"v21List",
	"v31ResultInArg0List",
}

var amd64RegInfoSet = map[string]bool{
	"v11": true, "v21": true, "v2k": true, "v2kv": true, "v2kk": true, "vkv": true, "v31": true, "v3kv": true, "vgpv": true, "vgp": true, "vfpv": true, "vfpkv": true,
	"w11": true, "w21": true, "w2k": true, "w2kw": true, "w2kk": true, "wkw": true, "w31": true, "w3kw": true, "wgpw": true, "wgp": true, "wfpw": true, "wfpkw": true,
	"wkwload": true, "v21load": true, "v31load": true, "v11load": true, "w21load": true, "w31load": true, "w2kload": true, "w2kwload": true, "w11load": true,
	"w3kwload": true, "w2kkload": true, "v31x0AtIn2": true,
}

var arm64RegInfoSet = map[string]bool{
	"v11":                 true,
	"v21":                 true,
	"v21Imm":              true,
	"v31":                 true,
	"vgp":                 true,
	"vgpv":                true,
	"vfpv":                true,
	"v11ImmIn1":           true,
	"v11Long":             true,
	"v11Narrow":           true,
	"v11ImmNarrow":        true,
	"v11ImmLong":          true,
	"v21Long":             true,
	"v11Long2":            true,
	"v21Narrow2":          true,
	"v21ImmNarrow2":       true,
	"v11ImmLong2":         true,
	"v21Long2":            true,
	"v21List":             true,
	"v31ResultInArg0List": true,
}

// arm64Arrangements contains the SIMD arrangement suffixes for ARM64 NEON.
// These correspond to the ARNG_* constants in cmd/internal/obj/arm64/a.out.go.
var arm64Arrangements = []string{
	"8B", "16B", "1D", "4H", "8H", "2S", "4S", "2D", "1Q", "B", "H", "S", "D",
}

const amd64RegInfoParams = "v11, v21, v2k, vkv, v2kv, v2kk, v31, v3kv, vgpv, vgp, vfpv, vfpkv, w11, w21, w2k, wkw, w2kw, w2kk, w31, w3kw, wgpw, wgp, wfpw, wfpkw,\n\twkwload, v21load, v31load, v11load, w21load, w31load, w2kload, w2kwload, w11load, w3kwload, w2kkload, v31x0AtIn2 regInfo"

const arm64RegInfoParams = "v11, v21, v31, vgp, vgpv, vfpv regInfo"

const amd64GeneratedHeader = `// Code generated by 'simdgen -o godefs -goroot $GOROOT -arch amd64 -xedPath $XED_PATH go_amd64.yaml types.yaml categories.yaml'; DO NOT EDIT.
`

const arm64GeneratedHeader = `// Code generated by 'simdgen -o godefs -goroot $GOROOT -arch arm64 -arm64Path $ARM64_ISA_PATH go_arm64.yaml types.yaml categories.yaml'; DO NOT EDIT.
`

// GetArchInfo returns architecture-specific information based on the target architecture.
func GetArchInfo(arch string) (ArchInfo, error) {
	switch arch {
	case "amd64":
		return ArchInfo{
			Arch:            "amd64",
			ArchUpper:       "AMD64",
			ObjArch:         "x86",
			RegInfoKeys:     amd64RegInfoKeys,
			RegInfoSet:      amd64RegInfoSet,
			RegInfoParams:   amd64RegInfoParams,
			GeneratedHeader: amd64GeneratedHeader,
		}, nil
	case "arm64":
		return ArchInfo{
			Arch:            "arm64",
			ArchUpper:       "ARM64",
			ObjArch:         "arm64",
			RegInfoKeys:     arm64RegInfoKeys,
			RegInfoSet:      arm64RegInfoSet,
			RegInfoParams:   arm64RegInfoParams,
			GeneratedHeader: arm64GeneratedHeader,
			Arrangements:    arm64Arrangements,
		}, nil
	default:
		return ArchInfo{}, fmt.Errorf("unsupported architecture: %s", arch)
	}
}

// CurrentArch returns the ArchInfo for the current FlagArch setting.
func CurrentArch() ArchInfo {
	info, err := GetArchInfo(*FlagArch)
	if err != nil {
		panic(err)
	}
	return info
}
