// 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 asmgen

var ArchARM64 = &Arch{
	Name:          "arm64",
	WordBits:      64,
	WordBytes:     8,
	CarrySafeLoop: true,

	regs: []string{
		// R18 is the platform register.
		// R27 is the assembler/linker temporary (which we could potentially use but don't).
		// R28 is g.
		// R29 is FP.
		// R30 is LR.
		"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9",
		"R10", "R11", "R12", "R13", "R14", "R15", "R16", "R17", "R19",
		"R20", "R21", "R22", "R23", "R24", "R25", "R26",
	},
	reg0: "ZR",

	mov:   "MOVD",
	add:   "ADD",
	adds:  "ADDS",
	adc:   "ADC",
	adcs:  "ADCS",
	sub:   "SUB",
	subs:  "SUBS",
	sbc:   "SBC",
	sbcs:  "SBCS",
	mul:   "MUL",
	mulhi: "UMULH",
	lsh:   "LSL",
	rsh:   "LSR",
	and:   "AND",
	or:    "ORR",
	xor:   "EOR",

	addWords: "ADD %[1]s<<3, %[2]s, %[3]s",

	jmpZero:    "CBZ %s, %s",
	jmpNonZero: "CBNZ %s, %s",

	loadIncN:  arm64LoadIncN,
	loadDecN:  arm64LoadDecN,
	storeIncN: arm64StoreIncN,
	storeDecN: arm64StoreDecN,
}

func arm64LoadIncN( *Asm,  RegPtr,  []Reg) {
	if len() == 1 {
		.Printf("\tMOVD.P %d(%s), %s\n", .Arch.WordBytes, , [0])
		return
	}
	.Printf("\tLDP.P %d(%s), (%s, %s)\n", len()*.Arch.WordBytes, , [0], [1])
	var  int
	for  = 2; +2 <= len();  += 2 {
		.Printf("\tLDP %d(%s), (%s, %s)\n", (-len())*.Arch.WordBytes, , [], [+1])
	}
	if  < len() {
		.Printf("\tMOVD %d(%s), %s\n", -1*.Arch.WordBytes, , [])
	}
}

func arm64LoadDecN( *Asm,  RegPtr,  []Reg) {
	if len() == 1 {
		.Printf("\tMOVD.W -%d(%s), %s\n", .Arch.WordBytes, , [0])
		return
	}
	.Printf("\tLDP.W %d(%s), (%s, %s)\n", -len()*.Arch.WordBytes, , [len()-1], [len()-2])
	var  int
	for  = 2; +2 <= len();  += 2 {
		.Printf("\tLDP %d(%s), (%s, %s)\n", *.Arch.WordBytes, , [len()-1-], [len()-2-])
	}
	if  < len() {
		.Printf("\tMOVD %d(%s), %s\n", *.Arch.WordBytes, , [0])
	}
}

func arm64StoreIncN( *Asm,  RegPtr,  []Reg) {
	if len() == 1 {
		.Printf("\tMOVD.P %s, %d(%s)\n", [0], .Arch.WordBytes, )
		return
	}
	.Printf("\tSTP.P (%s, %s), %d(%s)\n", [0], [1], len()*.Arch.WordBytes, )
	var  int
	for  = 2; +2 <= len();  += 2 {
		.Printf("\tSTP (%s, %s), %d(%s)\n", [], [+1], (-len())*.Arch.WordBytes, )
	}
	if  < len() {
		.Printf("\tMOVD %s, %d(%s)\n", [], -1*.Arch.WordBytes, )
	}
}

func arm64StoreDecN( *Asm,  RegPtr,  []Reg) {
	if len() == 1 {
		.Printf("\tMOVD.W %s, -%d(%s)\n", [0], .Arch.WordBytes, )
		return
	}
	.Printf("\tSTP.W (%s, %s), %d(%s)\n", [len()-1], [len()-2], -len()*.Arch.WordBytes, )
	var  int
	for  = 2; +2 <= len();  += 2 {
		.Printf("\tSTP (%s, %s), %d(%s)\n", [len()-1-], [len()-2-], *.Arch.WordBytes, )
	}
	if  < len() {
		.Printf("\tMOVD %s, %d(%s)\n", [0], *.Arch.WordBytes, )
	}
}