diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go index 403e70eee7..a724a3b6d9 100644 --- a/src/cmd/asm/internal/arch/arch.go +++ b/src/cmd/asm/internal/arch/arch.go @@ -9,6 +9,7 @@ import ( "cmd/internal/obj" "cmd/internal/obj/arm" "cmd/internal/obj/arm64" + "cmd/internal/obj/loong64" "cmd/internal/obj/mips" "cmd/internal/obj/ppc64" "cmd/internal/obj/riscv" @@ -60,6 +61,8 @@ func Set(GOARCH string, shared bool) *Arch { return archArm() case "arm64": return archArm64() + case "loong64": + return archLoong64(&loong64.Linkloong64) case "mips": return archMips(&mips.Linkmips) case "mipsle": @@ -502,6 +505,59 @@ func archMips64(linkArch *obj.LinkArch) *Arch { } } +func archLoong64(linkArch *obj.LinkArch) *Arch { + register := make(map[string]int16) + // Create maps for easy lookup of instruction names etc. + // Note that there is no list of names as there is for x86. + for i := loong64.REG_R0; i <= loong64.REG_R31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := loong64.REG_F0; i <= loong64.REG_F31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := loong64.REG_FCSR0; i <= loong64.REG_FCSR31; i++ { + register[obj.Rconv(i)] = int16(i) + } + for i := loong64.REG_FCC0; i <= loong64.REG_FCC31; i++ { + register[obj.Rconv(i)] = int16(i) + } + // Pseudo-registers. + register["SB"] = RSB + register["FP"] = RFP + register["PC"] = RPC + // Avoid unintentionally clobbering g using R22. + delete(register, "R22") + register["g"] = loong64.REG_R22 + register["RSB"] = loong64.REG_R31 + registerPrefix := map[string]bool{ + "F": true, + "FCSR": true, + "FCC": true, + "R": true, + } + + instructions := make(map[string]obj.As) + for i, s := range obj.Anames { + instructions[s] = obj.As(i) + } + for i, s := range loong64.Anames { + if obj.As(i) >= obj.A_ARCHSPECIFIC { + instructions[s] = obj.As(i) + obj.ABaseLoong64 + } + } + // Annoying alias. + instructions["JAL"] = loong64.AJAL + + return &Arch{ + LinkArch: linkArch, + Instructions: instructions, + Register: register, + RegisterPrefix: registerPrefix, + RegisterNumber: loong64RegisterNumber, + IsJump: jumpLoong64, + } +} + func archRISCV64(shared bool) *Arch { register := make(map[string]int16) diff --git a/src/cmd/asm/internal/arch/loong64.go b/src/cmd/asm/internal/arch/loong64.go new file mode 100644 index 0000000000..ebf842c1f2 --- /dev/null +++ b/src/cmd/asm/internal/arch/loong64.go @@ -0,0 +1,67 @@ +// 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" +) + +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 +} + +// IsLoong64CMP reports whether the op (as defined by an loong64.A* constant) is +// one of the CMP instructions that require special handling. +func IsLoong64CMP(op obj.As) bool { + switch op { + case loong64.ACMPEQF, loong64.ACMPEQD, loong64.ACMPGEF, loong64.ACMPGED, + loong64.ACMPGTF, loong64.ACMPGTD: + 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 +} + +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 + } + } + return 0, false +} diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go index 3afbec8b92..3babd4b677 100644 --- a/src/cmd/asm/internal/asm/asm.go +++ b/src/cmd/asm/internal/asm/asm.go @@ -460,6 +460,14 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) { prog.Reg = p.getRegister(prog, op, &a[1]) break } + if p.arch.Family == sys.Loong64 { + // 3-operand jumps. + // First two must be registers + target = &a[2] + prog.From = a[0] + prog.Reg = p.getRegister(prog, op, &a[1]) + break + } if p.arch.Family == sys.S390X { // 3-operand jumps. target = &a[2] @@ -620,6 +628,12 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.Reg = p.getRegister(prog, op, &a[1]) break } + } else if p.arch.Family == sys.Loong64 { + if arch.IsLoong64CMP(op) { + prog.From = a[0] + prog.Reg = p.getRegister(prog, op, &a[1]) + break + } } prog.From = a[0] prog.To = a[1] @@ -629,6 +643,10 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) prog.To = a[2] + case sys.Loong64: + prog.From = a[0] + prog.Reg = p.getRegister(prog, op, &a[1]) + prog.To = a[2] case sys.ARM: // Special cases. if arch.IsARMSTREX(op) {