// Copyright 2024 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 loong64asm import ( "fmt" "strings" ) // An Inst is a single instruction. type Inst struct { Op Op // Opcode mnemonic Enc uint32 // Raw encoding bits. Args Args // Instruction arguments, in Loong64 manual order. } func (i Inst) String() string { var op string = i.Op.String() var args []string for _, arg := range i.Args { if arg == nil { break } args = append(args, arg.String()) } switch i.Op { case OR: if i.Args[2].(Reg) == R0 { op = "move" args = args[0:2] } case ANDI: if i.Args[0].(Reg) == R0 && i.Args[1].(Reg) == R0 { return "nop" } case JIRL: if i.Args[0].(Reg) == R0 && i.Args[1].(Reg) == R1 && i.Args[2].(OffsetSimm).Imm == 0 { return "ret" } else if i.Args[0].(Reg) == R0 && i.Args[2].(OffsetSimm).Imm == 0 { return "jr " + args[1] } case BLT: if i.Args[0].(Reg) == R0 { op = "bgtz" args = args[1:] } else if i.Args[1].(Reg) == R0 { op = "bltz" args = append(args[:1], args[2:]...) } case BGE: if i.Args[0].(Reg) == R0 { op = "blez" args = args[1:] } else if i.Args[1].(Reg) == R0 { op = "bgez" args = append(args[:1], args[2:]...) } } if len(args) == 0 { return op } else { return op + " " + strings.Join(args, ", ") } } // An Op is an Loong64 opcode. type Op uint16 // NOTE: The actual Op values are defined in tables.go. // They are chosen to simplify instruction decoding and // are not a dense packing from 0 to N, although the // density is high, probably at least 90%. func (op Op) String() string { if (op >= Op(len(opstr))) || (opstr[op] == "") { return fmt.Sprintf("Op(%d)", int(op)) } return opstr[op] } // An Args holds the instruction arguments. // If an instruction has fewer than 5 arguments, // the final elements in the array are nil. type Args [5]Arg // An Arg is a single instruction argument type Arg interface { String() string } // A Reg is a single register. // The zero value denotes R0, not the absence of a register. type Reg uint16 const ( // General-purpose register R0 Reg = iota R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 R30 R31 // Float point register F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 ) func (r Reg) String() string { switch { case r == R0: return "$zero" case r == R1: return "$ra" case r == R2: return "$tp" case r == R3: return "$sp" case (r >= R4) && (r <= R11): return fmt.Sprintf("$a%d", int(r-R4)) case (r >= R12) && (r <= R20): return fmt.Sprintf("$t%d", int(r-R12)) case r == R21: return "$r21" case r == R22: return "$fp" case (r >= R23) && (r <= R31): return fmt.Sprintf("$s%d", int(r-R23)) case (r >= F0) && (r <= F7): return fmt.Sprintf("$fa%d", int(r-F0)) case (r >= F8) && (r <= F23): return fmt.Sprintf("$ft%d", int(r-F8)) case (r >= F24) && (r <= F31): return fmt.Sprintf("$fs%d", int(r-F24)) default: return fmt.Sprintf("Unknown(%d)", int(r)) } } // float control status register type Fcsr uint8 const ( FCSR0 Fcsr = iota FCSR1 FCSR2 FCSR3 ) func (f Fcsr) String() string { return fmt.Sprintf("$fcsr%d", uint8(f)) } // float condition flags register type Fcc uint8 const ( FCC0 Fcc = iota FCC1 FCC2 FCC3 FCC4 FCC5 FCC6 FCC7 ) func (f Fcc) String() string { return fmt.Sprintf("$fcc%d", uint8(f)) } // An Imm is an integer constant. type Uimm struct { Imm uint32 Decimal bool } func (i Uimm) String() string { if i.Decimal == true { return fmt.Sprintf("%d", i.Imm) } else { return fmt.Sprintf("%#x", i.Imm) } } type Simm16 struct { Imm int16 Width uint8 } func (si Simm16) String() string { return fmt.Sprintf("%d", int32(si.Imm)) } type Simm32 struct { Imm int32 Width uint8 } func (si Simm32) String() string { return fmt.Sprintf("%d", int32(si.Imm)) } type OffsetSimm struct { Imm int32 Width uint8 } func (o OffsetSimm) String() string { return fmt.Sprintf("%d", int32(o.Imm)) } type SaSimm int16 func (s SaSimm) String() string { return fmt.Sprintf("%#x", int(s)) } type CodeSimm int16 func (c CodeSimm) String() string { return fmt.Sprintf("%#x", int(c)) }