package riscv

import (
	"cmd/compile/internal/gc"
	"cmd/internal/obj"
	"cmd/internal/obj/riscv"
)

// This table gives the basic information about instruction generated by the
// compiler and processed in the optimizer.  Instructions not generated may be
// omitted.
//
// NOTE(prattmic): I believe that the gc.Size flags are used only for non-SSA
// peephole optimizations, and can thus be omitted for RISCV.
var progmap = map[obj.As]gc.ProgInfo{
	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
	obj.ATEXT:     {Flags: gc.Pseudo},
	obj.AFUNCDATA: {Flags: gc.Pseudo},
	obj.APCDATA:   {Flags: gc.Pseudo},
	obj.AUNDEF:    {Flags: gc.Break},
	obj.AUSEFIELD: {Flags: gc.OK},
	obj.AVARDEF:   {Flags: gc.Pseudo | gc.RightWrite},
	obj.AVARKILL:  {Flags: gc.Pseudo | gc.RightWrite},
	obj.AVARLIVE:  {Flags: gc.Pseudo | gc.LeftRead},
	obj.ARET:      {Flags: gc.Break},
	obj.AJMP:      {Flags: gc.Jump | gc.Break | gc.KillCarry},
	obj.ACALL:     {Flags: gc.RightAddr | gc.Call | gc.KillCarry},

	// NOP is an internal no-op that also stands for USED and SET
	// annotations.
	obj.ANOP: {Flags: gc.LeftRead | gc.RightWrite},

	// 2.5: Control Transfer Instructions
	riscv.ABEQ:  {Flags: gc.Cjmp | gc.LeftRead | gc.RegRead},
	riscv.ABNE:  {Flags: gc.Cjmp | gc.LeftRead | gc.RegRead},
	riscv.ABLT:  {Flags: gc.Cjmp | gc.LeftRead | gc.RegRead},
	riscv.ABLTU: {Flags: gc.Cjmp | gc.LeftRead | gc.RegRead},
	riscv.ABGE:  {Flags: gc.Cjmp | gc.LeftRead | gc.RegRead},
	riscv.ABGEU: {Flags: gc.Cjmp | gc.LeftRead | gc.RegRead},

	// 2.9: Environment Call and Breakpoints
	riscv.AECALL:  {Flags: gc.OK},
	riscv.AEBREAK: {Flags: gc.OK},

	// 4.2: Integer Computational Instructions
	riscv.AADDI:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.ASLTI:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.ASLTIU: {Flags: gc.LeftRead | gc.RightWrite},
	riscv.ASEQZ:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AANDI:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AORI:   {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AXORI:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.ASLLI:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.ASRLI:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.ASRAI:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AADD:   {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.ASLT:   {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.ASLTU:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.ASNEZ:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AAND:   {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AOR:    {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AXOR:   {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.ASLL:   {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.ASRL:   {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.ASUB:   {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.ASRA:   {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},

	// 4.3: Load and Store Instructions
	riscv.ALD:    {Flags: gc.LeftRead | gc.RightWrite | gc.Move},
	riscv.ASD:    {Flags: gc.LeftRead | gc.RightWrite | gc.Move},
	riscv.AMOV:   {Flags: gc.LeftRead | gc.RightWrite | gc.Move},
	riscv.AMOVW:  {Flags: gc.LeftRead | gc.RightWrite | gc.Move},
	riscv.AMOVWU: {Flags: gc.LeftRead | gc.RightWrite | gc.Move},
	riscv.AMOVH:  {Flags: gc.LeftRead | gc.RightWrite | gc.Move},
	riscv.AMOVHU: {Flags: gc.LeftRead | gc.RightWrite | gc.Move},
	riscv.AMOVB:  {Flags: gc.LeftRead | gc.RightWrite | gc.Move},
	riscv.AMOVBU: {Flags: gc.LeftRead | gc.RightWrite | gc.Move},

	// 5.1: Multiplication Operations
	riscv.AMUL:   {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AMULH:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AMULHU: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AMULW:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.ADIV:   {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.ADIVU:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AREM:   {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AREMU:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.ADIVW:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.ADIVUW: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AREMW:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AREMUW: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},

	// 7.5: Single-Precision Load and Store Instructions
	riscv.AMOVF: {Flags: gc.LeftRead | gc.RightWrite | gc.Move},

	// 7.6: Single-Precision Floating-Point Computational Instructions
	riscv.AFADDS:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFSUBS:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFMULS:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFDIVS:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFSQRTS: {Flags: gc.LeftRead | gc.RightWrite},

	// 7.7: Single-Precision Floating-Point Conversion and Move Instructions
	riscv.AFSGNJS:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFSGNJNS: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFNEGS:   {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFSGNJXS: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFCVTWS:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFCVTLS:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFCVTSW:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFCVTSL:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFMVSX:   {Flags: gc.LeftRead | gc.RightWrite},

	// 7.8: Single-Precision Floating-Point Compare Instructions
	riscv.AFEQS: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFNES: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFLTS: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFLES: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},

	// 8.2: Double-Precision Load and Store Instructions
	riscv.AMOVD: {Flags: gc.LeftRead | gc.RightWrite | gc.Move},

	// 8.3: Double-Precision Floating-Point Computational Instructions
	riscv.AFADDD:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFSUBD:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFMULD:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFDIVD:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFSQRTD: {Flags: gc.LeftRead | gc.RightWrite},

	// 8.4: Double-Precision Floating-Point Conversion and Move Instructions
	riscv.AFSGNJD:  {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFSGNJND: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFNEGD:   {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFSGNJXD: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFCVTWD:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFCVTLD:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFCVTDW:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFCVTDL:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFCVTSD:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFCVTDS:  {Flags: gc.LeftRead | gc.RightWrite},
	riscv.AFMVDX:   {Flags: gc.LeftRead | gc.RightWrite},

	// 8.5: Double-Precision Floating-Point Compare Instructions
	riscv.AFEQD: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFNED: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFLTD: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
	riscv.AFLED: {Flags: gc.LeftRead | gc.RegRead | gc.RightWrite},
}

func proginfo(p *obj.Prog) gc.ProgInfo {
	info, ok := progmap[p.As]
	if !ok {
		gc.Fatalf("proginfo missing prog %v", p.As)
	}

	return info
}
