//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
//	Portions Copyright © 1997-1999 Vita Nuova Limited
//	Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
//	Portions Copyright © 2004,2006 Bruce Ellis
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
//	Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
//	Portions Copyright © 2019 The Go Authors.  All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package riscv

import (
	"errors"
	"fmt"

	"cmd/internal/obj"
)

//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p riscv

const (
	// Base register numberings.
	REG_X0 = obj.RBaseRISCV + iota
	REG_X1
	REG_X2
	REG_X3
	REG_X4
	REG_X5
	REG_X6
	REG_X7
	REG_X8
	REG_X9
	REG_X10
	REG_X11
	REG_X12
	REG_X13
	REG_X14
	REG_X15
	REG_X16
	REG_X17
	REG_X18
	REG_X19
	REG_X20
	REG_X21
	REG_X22
	REG_X23
	REG_X24
	REG_X25
	REG_X26
	REG_X27
	REG_X28
	REG_X29
	REG_X30
	REG_X31

	// FP register numberings.
	REG_F0
	REG_F1
	REG_F2
	REG_F3
	REG_F4
	REG_F5
	REG_F6
	REG_F7
	REG_F8
	REG_F9
	REG_F10
	REG_F11
	REG_F12
	REG_F13
	REG_F14
	REG_F15
	REG_F16
	REG_F17
	REG_F18
	REG_F19
	REG_F20
	REG_F21
	REG_F22
	REG_F23
	REG_F24
	REG_F25
	REG_F26
	REG_F27
	REG_F28
	REG_F29
	REG_F30
	REG_F31

	// This marks the end of the register numbering.
	REG_END

	// General registers reassigned to ABI names.
	REG_ZERO = REG_X0
	REG_RA   = REG_X1 // aka REG_LR
	REG_SP   = REG_X2
	REG_GP   = REG_X3 // aka REG_SB
	REG_TP   = REG_X4
	REG_T0   = REG_X5
	REG_T1   = REG_X6
	REG_T2   = REG_X7
	REG_S0   = REG_X8
	REG_S1   = REG_X9
	REG_A0   = REG_X10
	REG_A1   = REG_X11
	REG_A2   = REG_X12
	REG_A3   = REG_X13
	REG_A4   = REG_X14
	REG_A5   = REG_X15
	REG_A6   = REG_X16
	REG_A7   = REG_X17
	REG_S2   = REG_X18
	REG_S3   = REG_X19
	REG_S4   = REG_X20
	REG_S5   = REG_X21
	REG_S6   = REG_X22
	REG_S7   = REG_X23
	REG_S8   = REG_X24
	REG_S9   = REG_X25
	REG_S10  = REG_X26 // aka REG_CTXT
	REG_S11  = REG_X27 // aka REG_G
	REG_T3   = REG_X28
	REG_T4   = REG_X29
	REG_T5   = REG_X30
	REG_T6   = REG_X31 // aka REG_TMP

	// Go runtime register names.
	REG_CTXT = REG_S10 // Context for closures.
	REG_G    = REG_S11 // G pointer.
	REG_LR   = REG_RA  // Link register.
	REG_TMP  = REG_T6  // Reserved for assembler use.

	// ABI names for floating point registers.
	REG_FT0  = REG_F0
	REG_FT1  = REG_F1
	REG_FT2  = REG_F2
	REG_FT3  = REG_F3
	REG_FT4  = REG_F4
	REG_FT5  = REG_F5
	REG_FT6  = REG_F6
	REG_FT7  = REG_F7
	REG_FS0  = REG_F8
	REG_FS1  = REG_F9
	REG_FA0  = REG_F10
	REG_FA1  = REG_F11
	REG_FA2  = REG_F12
	REG_FA3  = REG_F13
	REG_FA4  = REG_F14
	REG_FA5  = REG_F15
	REG_FA6  = REG_F16
	REG_FA7  = REG_F17
	REG_FS2  = REG_F18
	REG_FS3  = REG_F19
	REG_FS4  = REG_F20
	REG_FS5  = REG_F21
	REG_FS6  = REG_F22
	REG_FS7  = REG_F23
	REG_FS8  = REG_F24
	REG_FS9  = REG_F25
	REG_FS10 = REG_F26
	REG_FS11 = REG_F27
	REG_FT8  = REG_F28
	REG_FT9  = REG_F29
	REG_FT10 = REG_F30
	REG_FT11 = REG_F31

	// Names generated by the SSA compiler.
	REGSP = REG_SP
	REGG  = REG_G
)

// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-dwarf.adoc#dwarf-register-numbers
var RISCV64DWARFRegisters = map[int16]int16{
	// Integer Registers.
	REG_X0:  0,
	REG_X1:  1,
	REG_X2:  2,
	REG_X3:  3,
	REG_X4:  4,
	REG_X5:  5,
	REG_X6:  6,
	REG_X7:  7,
	REG_X8:  8,
	REG_X9:  9,
	REG_X10: 10,
	REG_X11: 11,
	REG_X12: 12,
	REG_X13: 13,
	REG_X14: 14,
	REG_X15: 15,
	REG_X16: 16,
	REG_X17: 17,
	REG_X18: 18,
	REG_X19: 19,
	REG_X20: 20,
	REG_X21: 21,
	REG_X22: 22,
	REG_X23: 23,
	REG_X24: 24,
	REG_X25: 25,
	REG_X26: 26,
	REG_X27: 27,
	REG_X28: 28,
	REG_X29: 29,
	REG_X30: 30,
	REG_X31: 31,

	// Floating-Point Registers.
	REG_F0:  32,
	REG_F1:  33,
	REG_F2:  34,
	REG_F3:  35,
	REG_F4:  36,
	REG_F5:  37,
	REG_F6:  38,
	REG_F7:  39,
	REG_F8:  40,
	REG_F9:  41,
	REG_F10: 42,
	REG_F11: 43,
	REG_F12: 44,
	REG_F13: 45,
	REG_F14: 46,
	REG_F15: 47,
	REG_F16: 48,
	REG_F17: 49,
	REG_F18: 50,
	REG_F19: 51,
	REG_F20: 52,
	REG_F21: 53,
	REG_F22: 54,
	REG_F23: 55,
	REG_F24: 56,
	REG_F25: 57,
	REG_F26: 58,
	REG_F27: 59,
	REG_F28: 60,
	REG_F29: 61,
	REG_F30: 62,
	REG_F31: 63,
}

// Prog.Mark flags.
const (
	// USES_REG_TMP indicates that a machine instruction generated from the
	// corresponding *obj.Prog uses the temporary register.
	USES_REG_TMP = 1 << iota

	// NEED_JAL_RELOC is set on JAL instructions to indicate that a
	// R_RISCV_JAL relocation is needed.
	NEED_JAL_RELOC

	// NEED_CALL_RELOC is set on an AUIPC instruction to indicate that it
	// is the first instruction in an AUIPC + JAL pair that needs a
	// R_RISCV_CALL relocation.
	NEED_CALL_RELOC

	// NEED_PCREL_ITYPE_RELOC is set on AUIPC instructions to indicate that
	// it is the first instruction in an AUIPC + I-type pair that needs a
	// R_RISCV_PCREL_ITYPE relocation.
	NEED_PCREL_ITYPE_RELOC

	// NEED_PCREL_STYPE_RELOC is set on AUIPC instructions to indicate that
	// it is the first instruction in an AUIPC + S-type pair that needs a
	// R_RISCV_PCREL_STYPE relocation.
	NEED_PCREL_STYPE_RELOC
)

// RISC-V mnemonics, as defined in the "opcodes" and "opcodes-pseudo" files
// at https://github.com/riscv/riscv-opcodes.
//
// As well as some pseudo-mnemonics (e.g. MOV) used only in the assembler.
//
// See also "The RISC-V Instruction Set Manual" at https://riscv.org/specifications/.
//
// If you modify this table, you MUST run 'go generate' to regenerate anames.go!
const (
	// Unprivileged ISA (Document Version 20190608-Base-Ratified)

	// 2.4: Integer Computational Instructions
	AADDI = obj.ABaseRISCV + obj.A_ARCHSPECIFIC + iota
	ASLTI
	ASLTIU
	AANDI
	AORI
	AXORI
	ASLLI
	ASRLI
	ASRAI
	ALUI
	AAUIPC
	AADD
	ASLT
	ASLTU
	AAND
	AOR
	AXOR
	ASLL
	ASRL
	ASUB
	ASRA

	// 2.5: Control Transfer Instructions
	AJAL
	AJALR
	ABEQ
	ABNE
	ABLT
	ABLTU
	ABGE
	ABGEU

	// 2.6: Load and Store Instructions
	ALW
	ALWU
	ALH
	ALHU
	ALB
	ALBU
	ASW
	ASH
	ASB

	// 2.7: Memory Ordering Instructions
	AFENCE
	AFENCETSO
	APAUSE

	// 5.2: Integer Computational Instructions (RV64I)
	AADDIW
	ASLLIW
	ASRLIW
	ASRAIW
	AADDW
	ASLLW
	ASRLW
	ASUBW
	ASRAW

	// 5.3: Load and Store Instructions (RV64I)
	ALD
	ASD

	// 7.1: Multiplication Operations
	AMUL
	AMULH
	AMULHU
	AMULHSU
	AMULW
	ADIV
	ADIVU
	AREM
	AREMU
	ADIVW
	ADIVUW
	AREMW
	AREMUW

	// 8.2: Load-Reserved/Store-Conditional Instructions
	ALRD
	ASCD
	ALRW
	ASCW

	// 8.3: Atomic Memory Operations
	AAMOSWAPD
	AAMOADDD
	AAMOANDD
	AAMOORD
	AAMOXORD
	AAMOMAXD
	AAMOMAXUD
	AAMOMIND
	AAMOMINUD
	AAMOSWAPW
	AAMOADDW
	AAMOANDW
	AAMOORW
	AAMOXORW
	AAMOMAXW
	AAMOMAXUW
	AAMOMINW
	AAMOMINUW

	// 10.1: Base Counters and Timers
	ARDCYCLE
	ARDCYCLEH
	ARDTIME
	ARDTIMEH
	ARDINSTRET
	ARDINSTRETH

	// 11.2: Floating-Point Control and Status Register
	AFRCSR
	AFSCSR
	AFRRM
	AFSRM
	AFRFLAGS
	AFSFLAGS
	AFSRMI
	AFSFLAGSI

	// 11.5: Single-Precision Load and Store Instructions
	AFLW
	AFSW

	// 11.6: Single-Precision Floating-Point Computational Instructions
	AFADDS
	AFSUBS
	AFMULS
	AFDIVS
	AFMINS
	AFMAXS
	AFSQRTS
	AFMADDS
	AFMSUBS
	AFNMADDS
	AFNMSUBS

	// 11.7: Single-Precision Floating-Point Conversion and Move Instructions
	AFCVTWS
	AFCVTLS
	AFCVTSW
	AFCVTSL
	AFCVTWUS
	AFCVTLUS
	AFCVTSWU
	AFCVTSLU
	AFSGNJS
	AFSGNJNS
	AFSGNJXS
	AFMVXS
	AFMVSX
	AFMVXW
	AFMVWX

	// 11.8: Single-Precision Floating-Point Compare Instructions
	AFEQS
	AFLTS
	AFLES

	// 11.9: Single-Precision Floating-Point Classify Instruction
	AFCLASSS

	// 12.3: Double-Precision Load and Store Instructions
	AFLD
	AFSD

	// 12.4: Double-Precision Floating-Point Computational Instructions
	AFADDD
	AFSUBD
	AFMULD
	AFDIVD
	AFMIND
	AFMAXD
	AFSQRTD
	AFMADDD
	AFMSUBD
	AFNMADDD
	AFNMSUBD

	// 12.5: Double-Precision Floating-Point Conversion and Move Instructions
	AFCVTWD
	AFCVTLD
	AFCVTDW
	AFCVTDL
	AFCVTWUD
	AFCVTLUD
	AFCVTDWU
	AFCVTDLU
	AFCVTSD
	AFCVTDS
	AFSGNJD
	AFSGNJND
	AFSGNJXD
	AFMVXD
	AFMVDX

	// 12.6: Double-Precision Floating-Point Compare Instructions
	AFEQD
	AFLTD
	AFLED

	// 12.7: Double-Precision Floating-Point Classify Instruction
	AFCLASSD

	// 13.1 Quad-Precision Load and Store Instructions
	AFLQ
	AFSQ

	// 13.2: Quad-Precision Computational Instructions
	AFADDQ
	AFSUBQ
	AFMULQ
	AFDIVQ
	AFMINQ
	AFMAXQ
	AFSQRTQ
	AFMADDQ
	AFMSUBQ
	AFNMADDQ
	AFNMSUBQ

	// 13.3 Quad-Precision Convert and Move Instructions
	AFCVTWQ
	AFCVTLQ
	AFCVTSQ
	AFCVTDQ
	AFCVTQW
	AFCVTQL
	AFCVTQS
	AFCVTQD
	AFCVTWUQ
	AFCVTLUQ
	AFCVTQWU
	AFCVTQLU
	AFSGNJQ
	AFSGNJNQ
	AFSGNJXQ

	// 13.4 Quad-Precision Floating-Point Compare Instructions
	AFEQQ
	AFLEQ
	AFLTQ

	// 13.5 Quad-Precision Floating-Point Classify Instruction
	AFCLASSQ

	// Privileged ISA (Version 20190608-Priv-MSU-Ratified)

	// 3.1.9: Instructions to Access CSRs
	ACSRRW
	ACSRRS
	ACSRRC
	ACSRRWI
	ACSRRSI
	ACSRRCI

	// 3.2.1: Environment Call and Breakpoint
	AECALL
	ASCALL
	AEBREAK
	ASBREAK

	// 3.2.2: Trap-Return Instructions
	AMRET
	ASRET
	ADRET

	// 3.2.3: Wait for Interrupt
	AWFI

	// 4.2.1: Supervisor Memory-Management Fence Instruction
	ASFENCEVMA

	//
	// RISC-V Bit-Manipulation ISA-extensions (1.0)
	//

	// 1.1: Address Generation Instructions (Zba)
	AADDUW
	ASH1ADD
	ASH1ADDUW
	ASH2ADD
	ASH2ADDUW
	ASH3ADD
	ASH3ADDUW
	ASLLIUW

	// 1.2: Basic Bit Manipulation (Zbb)
	AANDN
	AORN
	AXNOR
	ACLZ
	ACLZW
	ACTZ
	ACTZW
	ACPOP
	ACPOPW
	AMAX
	AMAXU
	AMIN
	AMINU
	ASEXTB
	ASEXTH
	AZEXTH

	// 1.3: Bitwise Rotation (Zbb)
	AROL
	AROLW
	AROR
	ARORI
	ARORIW
	ARORW
	AORCB
	AREV8

	// 1.5: Single-bit Instructions (Zbs)
	ABCLR
	ABCLRI
	ABEXT
	ABEXTI
	ABINV
	ABINVI
	ABSET
	ABSETI

	// The escape hatch. Inserts a single 32-bit word.
	AWORD

	// Pseudo-instructions.  These get translated by the assembler into other
	// instructions, based on their operands.
	ABEQZ
	ABGEZ
	ABGT
	ABGTU
	ABGTZ
	ABLE
	ABLEU
	ABLEZ
	ABLTZ
	ABNEZ
	AFABSD
	AFABSS
	AFNEGD
	AFNEGS
	AFNED
	AFNES
	AMOV
	AMOVB
	AMOVBU
	AMOVF
	AMOVD
	AMOVH
	AMOVHU
	AMOVW
	AMOVWU
	ANEG
	ANEGW
	ANOT
	ASEQZ
	ASNEZ

	// End marker
	ALAST
)

// opSuffix encoding to uint8 which fit into p.Scond
var rmSuffixSet = map[string]uint8{
	"RNE": RM_RNE,
	"RTZ": RM_RTZ,
	"RDN": RM_RDN,
	"RUP": RM_RUP,
	"RMM": RM_RMM,
}

const rmSuffixBit uint8 = 1 << 7

func rmSuffixEncode(s string) (uint8, error) {
	if s == "" {
		return 0, errors.New("empty suffix")
	}
	enc, ok := rmSuffixSet[s]
	if !ok {
		return 0, fmt.Errorf("invalid encoding for unknown suffix:%q", s)
	}
	return enc | rmSuffixBit, nil
}

func rmSuffixString(u uint8) (string, error) {
	if u&rmSuffixBit == 0 {
		return "", fmt.Errorf("invalid suffix, require round mode bit:%x", u)
	}

	u &^= rmSuffixBit
	for k, v := range rmSuffixSet {
		if v == u {
			return k, nil
		}
	}
	return "", fmt.Errorf("unknown suffix:%x", u)
}

const (
	RM_RNE uint8 = iota // Round to Nearest, ties to Even
	RM_RTZ              // Round towards Zero
	RM_RDN              // Round Down
	RM_RUP              // Round Up
	RM_RMM              // Round to Nearest, ties to Max Magnitude
)

// All unary instructions which write to their arguments (as opposed to reading
// from them) go here. The assembly parser uses this information to populate
// its AST in a semantically reasonable way.
//
// Any instructions not listed here are assumed to either be non-unary or to read
// from its argument.
var unaryDst = map[obj.As]bool{
	ARDCYCLE:    true,
	ARDCYCLEH:   true,
	ARDTIME:     true,
	ARDTIMEH:    true,
	ARDINSTRET:  true,
	ARDINSTRETH: true,
}

// Instruction encoding masks.
const (
	// BTypeImmMask is a mask including only the immediate portion of
	// B-type instructions.
	BTypeImmMask = 0xfe000f80

	// CBTypeImmMask is a mask including only the immediate portion of
	// CB-type instructions.
	CBTypeImmMask = 0x1c7c

	// CJTypeImmMask is a mask including only the immediate portion of
	// CJ-type instructions.
	CJTypeImmMask = 0x1f7c

	// ITypeImmMask is a mask including only the immediate portion of
	// I-type instructions.
	ITypeImmMask = 0xfff00000

	// JTypeImmMask is a mask including only the immediate portion of
	// J-type instructions.
	JTypeImmMask = 0xfffff000

	// STypeImmMask is a mask including only the immediate portion of
	// S-type instructions.
	STypeImmMask = 0xfe000f80

	// UTypeImmMask is a mask including only the immediate portion of
	// U-type instructions.
	UTypeImmMask = 0xfffff000
)
