// Copyright 2022 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. // This file encapsulates some of the odd characteristics of the // Loong64 (LoongArch64) instruction set, to minimize its interaction // with the core of the assembler. package arch import ( "cmd/internal/obj" "cmd/internal/obj/loong64" "errors" "fmt" ) func jumpLoong64(word string) bool { switch word { case "BEQ", "BFPF", "BFPT", "BLTZ", "BGEZ", "BLEZ", "BGTZ", "BLT", "BLTU", "JIRL", "BNE", "BGE", "BGEU", "JMP", "JAL", "CALL": return true } return false } // IsLoong64MUL reports whether the op (as defined by an loong64.A* constant) is // one of the MUL/DIV/REM instructions that require special handling. func IsLoong64MUL(op obj.As) bool { switch op { case loong64.AMUL, loong64.AMULU, loong64.AMULV, loong64.AMULVU, loong64.ADIV, loong64.ADIVU, loong64.ADIVV, loong64.ADIVVU, loong64.AREM, loong64.AREMU, loong64.AREMV, loong64.AREMVU: return true } return false } // IsLoong64RDTIME reports whether the op (as defined by an loong64.A* // constant) is one of the RDTIMELW/RDTIMEHW/RDTIMED instructions that // require special handling. func IsLoong64RDTIME(op obj.As) bool { switch op { case loong64.ARDTIMELW, loong64.ARDTIMEHW, loong64.ARDTIMED: return true } return false } func IsLoong64AMO(op obj.As) bool { return loong64.IsAtomicInst(op) } var loong64ElemExtMap = map[string]int16{ "B": loong64.ARNG_B, "H": loong64.ARNG_H, "W": loong64.ARNG_W, "V": loong64.ARNG_V, "BU": loong64.ARNG_BU, "HU": loong64.ARNG_HU, "WU": loong64.ARNG_WU, "VU": loong64.ARNG_VU, } var loong64LsxArngExtMap = map[string]int16{ "B16": loong64.ARNG_16B, "H8": loong64.ARNG_8H, "W4": loong64.ARNG_4W, "V2": loong64.ARNG_2V, } var loong64LasxArngExtMap = map[string]int16{ "B32": loong64.ARNG_32B, "H16": loong64.ARNG_16H, "W8": loong64.ARNG_8W, "V4": loong64.ARNG_4V, "Q2": loong64.ARNG_2Q, } // Loong64RegisterExtension constructs an Loong64 register with extension or arrangement. func Loong64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error { var ok bool var arng_type int16 var simd_type int16 switch { case reg >= loong64.REG_V0 && reg <= loong64.REG_V31: simd_type = loong64.LSX case reg >= loong64.REG_X0 && reg <= loong64.REG_X31: simd_type = loong64.LASX default: return errors.New("Loong64 extension: invalid LSX/LASX register: " + fmt.Sprintf("%d", reg)) } if isIndex { arng_type, ok = loong64ElemExtMap[ext] if !ok { return errors.New("Loong64 extension: invalid LSX/LASX arrangement type: " + ext) } a.Reg = loong64.REG_ELEM a.Reg += ((reg & loong64.EXT_REG_MASK) << loong64.EXT_REG_SHIFT) a.Reg += ((arng_type & loong64.EXT_TYPE_MASK) << loong64.EXT_TYPE_SHIFT) a.Reg += ((simd_type & loong64.EXT_SIMDTYPE_MASK) << loong64.EXT_SIMDTYPE_SHIFT) a.Index = num } else { switch simd_type { case loong64.LSX: arng_type, ok = loong64LsxArngExtMap[ext] if !ok { return errors.New("Loong64 extension: invalid LSX arrangement type: " + ext) } case loong64.LASX: arng_type, ok = loong64LasxArngExtMap[ext] if !ok { return errors.New("Loong64 extension: invalid LASX arrangement type: " + ext) } } a.Reg = loong64.REG_ARNG a.Reg += ((reg & loong64.EXT_REG_MASK) << loong64.EXT_REG_SHIFT) a.Reg += ((arng_type & loong64.EXT_TYPE_MASK) << loong64.EXT_TYPE_SHIFT) a.Reg += ((simd_type & loong64.EXT_SIMDTYPE_MASK) << loong64.EXT_SIMDTYPE_SHIFT) } return nil } func loong64RegisterNumber(name string, n int16) (int16, bool) { switch name { case "F": if 0 <= n && n <= 31 { return loong64.REG_F0 + n, true } case "FCSR": if 0 <= n && n <= 31 { return loong64.REG_FCSR0 + n, true } case "FCC": if 0 <= n && n <= 31 { return loong64.REG_FCC0 + n, true } case "R": if 0 <= n && n <= 31 { return loong64.REG_R0 + n, true } case "V": if 0 <= n && n <= 31 { return loong64.REG_V0 + n, true } case "X": if 0 <= n && n <= 31 { return loong64.REG_X0 + n, true } } return 0, false }