loong64: Implement loong64 GNU and plan9 format disassembler Loong64 documentation: https://github.com/loongson/LoongArch-Documentation.git Change-Id: Iff47bdcfc787f69361be510bc4784fe91e10431c Co-authored-by: huangqiqi <huangqiqi@loongson.cn> Co-authored-by: chenguoqi <chenguoqi@loongson.cn> Reviewed-on: https://go-review.googlesource.com/c/arch/+/358854 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: sophie zhao <zhaoxiaolin@loongson.cn> Reviewed-by: abner chenc <chenguoqi@loongson.cn> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Qiqi Huang <huangqiqi@loongson.cn> Reviewed-by: Zxilly Chou <zxilly@outlook.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
diff --git a/loong64/loong64asm/arg.go b/loong64/loong64asm/arg.go new file mode 100644 index 0000000..460af3d --- /dev/null +++ b/loong64/loong64asm/arg.go
@@ -0,0 +1,93 @@ +// 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 + +// Naming for Go decoder arguments: +// +// - arg_fd: a Floating Point operand register fd encoded in the fd[4:0] field +// +// - arg_fj: a Floating Point operand register fj encoded in the fj[9:5] field +// +// - arg_fk: a Floating Point operand register fk encoded in the fk[14:10] field +// +// - arg_fa: a Floating Point operand register fa encoded in the fa[19:15] field +// +// - arg_rd: a general-purpose register rd encoded in the rd[4:0] field +// +// - arg_rj: a general-purpose register rj encoded in the rj[9:5] field +// +// - arg_rk: a general-purpose register rk encoded in the rk[14:10] field +// +// - arg_fcsr_4_0: float control status register encoded in [4:0] field +// +// - arg_cd_2_0: condition flag register encoded in [2:0] field +// +// - arg_sa2_16_15: shift bits constant encoded in [16:15] field +// +// - arg_code_14_0: arg for exception process routine encoded in [14:0] field +// +// - arg_ui5_14_10: 5bits unsigned immediate +// +// - arg_lsbw: For details, please refer to chapter 2.2.3.8 of instruction manual +// +// - arg_msbw: For details, please refer to chapter 2.2.3.9 of instruction manual +// +// - arg_hint_4_0: hint field implied the prefetch type and the data should fetch to cache's level +// 0: load to data cache level 1 +// 8: store to data cache level 1 +// other: no define +// +// - arg_si12_21_10: 12bits signed immediate + +type instArg uint16 + +const ( + _ instArg = iota + // 1-5 + arg_fd + arg_fj + arg_fk + arg_fa + arg_rd + // 6-10 + arg_rj + arg_rk + arg_op_4_0 + arg_fcsr_4_0 + arg_fcsr_9_5 + // 11-15 + arg_csr_23_10 + arg_cd + arg_cj + arg_ca + arg_sa2_16_15 + // 16-20 + arg_sa3_17_15 + arg_code_4_0 + arg_code_14_0 + arg_ui5_14_10 + arg_ui6_15_10 + // 21-25 + arg_ui12_21_10 + arg_lsbw + arg_msbw + arg_lsbd + arg_msbd + // 26-30 + arg_hint_4_0 + arg_hint_14_0 + arg_level_14_0 + arg_level_17_10 + arg_seq_17_10 + // 31-35 + arg_si12_21_10 + arg_si14_23_10 + arg_si16_25_10 + arg_si20_24_5 + arg_offset_20_0 + // 36~ + arg_offset_25_0 + arg_offset_15_0 +)
diff --git a/loong64/loong64asm/decode.go b/loong64/loong64asm/decode.go new file mode 100644 index 0000000..3aca007 --- /dev/null +++ b/loong64/loong64asm/decode.go
@@ -0,0 +1,269 @@ +// 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 ( + "encoding/binary" + "fmt" +) + +type instArgs [5]instArg + +// An instFormat describes the format of an instruction encoding. +type instFormat struct { + mask uint32 + value uint32 + op Op + // args describe how to decode the instruction arguments. + // args is stored as a fixed-size array. + // if there are fewer than len(args) arguments, args[i] == 0 marks + // the end of the argument list. + args instArgs +} + +var ( + errShort = fmt.Errorf("truncated instruction") + errUnknown = fmt.Errorf("unknown instruction") +) + +var decoderCover []bool + +func init() { + decoderCover = make([]bool, len(instFormats)) +} + +// Decode decodes the 4 bytes in src as a single instruction. +func Decode(src []byte) (inst Inst, err error) { + if len(src) < 4 { + return Inst{}, errShort + } + + x := binary.LittleEndian.Uint32(src) + +Search: + for i := range instFormats { + f := &instFormats[i] + + if (x & f.mask) != f.value { + continue + } + + // Decode args. + var args Args + for j, aop := range f.args { + if aop == 0 { + break + } + + arg := decodeArg(aop, x, i) + if arg == nil { + // Cannot decode argument + continue Search + } + + args[j] = arg + } + + decoderCover[i] = true + inst = Inst{ + Op: f.op, + Args: args, + Enc: x, + } + return inst, nil + } + + return Inst{}, errUnknown +} + +// decodeArg decodes the arg described by aop from the instruction bits x. +// It returns nil if x cannot be decoded according to aop. +func decodeArg(aop instArg, x uint32, index int) Arg { + switch aop { + case arg_fd: + return F0 + Reg(x&((1<<5)-1)) + + case arg_fj: + return F0 + Reg((x>>5)&((1<<5)-1)) + + case arg_fk: + return F0 + Reg((x>>10)&((1<<5)-1)) + + case arg_fa: + return F0 + Reg((x>>15)&((1<<5)-1)) + + case arg_rd: + return R0 + Reg(x&((1<<5)-1)) + + case arg_rj: + return R0 + Reg((x>>5)&((1<<5)-1)) + + case arg_rk: + return R0 + Reg((x>>10)&((1<<5)-1)) + + case arg_fcsr_4_0: + return FCSR0 + Fcsr(x&((1<<5)-1)) + + case arg_fcsr_9_5: + return FCSR0 + Fcsr((x>>5)&((1<<5)-1)) + + case arg_cd: + return FCC0 + Fcc(x&((1<<3)-1)) + + case arg_cj: + return FCC0 + Fcc((x>>5)&((1<<3)-1)) + + case arg_ca: + return FCC0 + Fcc((x>>15)&((1<<3)-1)) + + case arg_op_4_0: + tmp := x & ((1 << 5) - 1) + return Uimm{tmp, false} + + case arg_csr_23_10: + tmp := (x >> 10) & ((1 << 14) - 1) + return Uimm{tmp, false} + + case arg_sa2_16_15: + f := &instFormats[index] + tmp := SaSimm((x >> 15) & ((1 << 2) - 1)) + if (f.op == ALSL_D) || (f.op == ALSL_W) || (f.op == ALSL_WU) { + return tmp + 1 + } else { + return tmp + 0 + } + + case arg_sa3_17_15: + return SaSimm((x >> 15) & ((1 << 3) - 1)) + + case arg_code_4_0: + return CodeSimm(x & ((1 << 5) - 1)) + + case arg_code_14_0: + return CodeSimm(x & ((1 << 15) - 1)) + + case arg_ui5_14_10: + tmp := (x >> 10) & ((1 << 5) - 1) + return Uimm{tmp, false} + + case arg_ui6_15_10: + tmp := (x >> 10) & ((1 << 6) - 1) + return Uimm{tmp, false} + + case arg_ui12_21_10: + tmp := ((x >> 10) & ((1 << 12) - 1) & 0xfff) + return Uimm{tmp, false} + + case arg_lsbw: + tmp := (x >> 10) & ((1 << 5) - 1) + return Uimm{tmp, false} + + case arg_msbw: + tmp := (x >> 16) & ((1 << 5) - 1) + return Uimm{tmp, false} + + case arg_lsbd: + tmp := (x >> 10) & ((1 << 6) - 1) + return Uimm{tmp, false} + + case arg_msbd: + tmp := (x >> 16) & ((1 << 6) - 1) + return Uimm{tmp, false} + + case arg_hint_4_0: + tmp := x & ((1 << 5) - 1) + return Uimm{tmp, false} + + case arg_hint_14_0: + tmp := x & ((1 << 15) - 1) + return Uimm{tmp, false} + + case arg_level_14_0: + tmp := x & ((1 << 15) - 1) + return Uimm{tmp, false} + + case arg_level_17_10: + tmp := (x >> 10) & ((1 << 8) - 1) + return Uimm{tmp, false} + + case arg_seq_17_10: + tmp := (x >> 10) & ((1 << 8) - 1) + return Uimm{tmp, false} + + case arg_si12_21_10: + var tmp int16 + + // no int12, so sign-extend a 12-bit signed to 16-bit signed + if (x & 0x200000) == 0x200000 { + tmp = int16(((x >> 10) & ((1 << 12) - 1)) | 0xf000) + } else { + tmp = int16(((x >> 10) & ((1 << 12) - 1)) | 0x0000) + } + return Simm16{tmp, 12} + + case arg_si14_23_10: + var tmp int32 + if (x & 0x800000) == 0x800000 { + tmp = int32((((x >> 10) & ((1 << 14) - 1)) << 2) | 0xffff0000) + } else { + tmp = int32((((x >> 10) & ((1 << 14) - 1)) << 2) | 0x00000000) + } + return Simm32{tmp, 14} + + case arg_si16_25_10: + var tmp int32 + + if (x & 0x2000000) == 0x2000000 { + tmp = int32(((x >> 10) & ((1 << 16) - 1)) | 0xffff0000) + } else { + tmp = int32(((x >> 10) & ((1 << 16) - 1)) | 0x00000000) + } + + return Simm32{tmp, 16} + + case arg_si20_24_5: + var tmp int32 + if (x & 0x1000000) == 0x1000000 { + tmp = int32(((x >> 5) & ((1 << 20) - 1)) | 0xfff00000) + } else { + tmp = int32(((x >> 5) & ((1 << 20) - 1)) | 0x00000000) + } + return Simm32{tmp, 20} + + case arg_offset_20_0: + var tmp int32 + + if (x & 0x10) == 0x10 { + tmp = int32(((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 21) - 1)) << 2) | 0xff800000) + } else { + tmp = int32((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 21) - 1)) << 2) + } + + return OffsetSimm{tmp, 21} + + case arg_offset_15_0: + var tmp int32 + if (x & 0x2000000) == 0x2000000 { + tmp = int32((((x >> 10) & ((1 << 16) - 1)) << 2) | 0xfffc0000) + } else { + tmp = int32((((x >> 10) & ((1 << 16) - 1)) << 2) | 0x00000000) + } + + return OffsetSimm{tmp, 16} + + case arg_offset_25_0: + var tmp int32 + + if (x & 0x200) == 0x200 { + tmp = int32(((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 26) - 1)) << 2) | 0xf0000000) + } else { + tmp = int32(((((x << 16) | ((x >> 10) & ((1 << 16) - 1))) & ((1 << 26) - 1)) << 2) | 0x00000000) + } + + return OffsetSimm{tmp, 26} + default: + return nil + } +}
diff --git a/loong64/loong64asm/decode_test.go b/loong64/loong64asm/decode_test.go new file mode 100644 index 0000000..74a3277 --- /dev/null +++ b/loong64/loong64asm/decode_test.go
@@ -0,0 +1,76 @@ +// 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 ( + "encoding/hex" + "io/ioutil" + "path/filepath" + "strings" + "testing" +) + +func testDecode(t *testing.T, syntax string) { + input := filepath.Join("testdata", syntax+"cases.txt") + data, err := ioutil.ReadFile(input) + if err != nil { + t.Fatal(err) + } + all := string(data) + for strings.Contains(all, "\t\t") { + all = strings.Replace(all, "\t\t", "\t", -1) + } + for _, line := range strings.Split(all, "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + f := strings.SplitN(line, "\t", 2) + i := strings.Index(f[0], "|") + if i < 0 { + t.Errorf("parsing %q: missing | separator", f[0]) + continue + } + if i%2 != 0 { + t.Errorf("parsing %q: misaligned | separator", f[0]) + } + code, err := hex.DecodeString(f[0][:i] + f[0][i+1:]) + if err != nil { + t.Errorf("parsing %q: %v", f[0], err) + continue + } + asm := f[1] + inst, decodeErr := Decode(code) + if decodeErr != nil && decodeErr != errUnknown { + // Some rarely used system instructions are not supported + // Following logicals will filter such unknown instructions + t.Errorf("parsing %x: %s", code, decodeErr) + continue + } + var out string + switch syntax { + case "gnu": + out = GNUSyntax(inst) + case "plan9": + out = GoSyntax(inst, 0, nil) + default: + t.Errorf("unknown syntax %q", syntax) + continue + } + + // var out string + if asm != out || len(asm) != len(out) { + t.Errorf("Decode(%s) [%s] = %s want %s", f[0], syntax, out, asm) + } + } +} + +func TestDecodeGNUSyntax(t *testing.T) { + testDecode(t, "gnu") +} + +func TestDecodeGoSyntax(t *testing.T) { + testDecode(t, "plan9") +}
diff --git a/loong64/loong64asm/ext_test.go b/loong64/loong64asm/ext_test.go new file mode 100644 index 0000000..5c90586 --- /dev/null +++ b/loong64/loong64asm/ext_test.go
@@ -0,0 +1,405 @@ +// 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. + +// Support for testing against external disassembler program. + +package loong64asm + +import ( + "bufio" + "bytes" + "encoding/hex" + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "math/rand" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "time" +) + +var ( + dumpTest = flag.Bool("dump", false, "dump all encodings") + mismatch = flag.Bool("mismatch", false, "log allowed mismatches") + keep = flag.Bool("keep", false, "keep object files around") + debug = false +) + +// An ExtInst represents a single decoded instruction parsed +// from an external disassembler's output. +type ExtInst struct { + addr uint64 + enc [4]byte + nenc int + text string +} + +func (r ExtInst) String() string { + return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text) +} + +// An ExtDis is a connection between an external disassembler and a test. +type ExtDis struct { + Dec chan ExtInst + File *os.File + Size int + Cmd *exec.Cmd +} + +// Run runs the given command - the external disassembler - and returns +// a buffered reader of its standard output. +func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) { + if *keep { + log.Printf("%s\n", strings.Join(cmd, " ")) + } + ext.Cmd = exec.Command(cmd[0], cmd[1:]...) + out, err := ext.Cmd.StdoutPipe() + if err != nil { + return nil, fmt.Errorf("stdoutpipe: %v", err) + } + if err := ext.Cmd.Start(); err != nil { + return nil, fmt.Errorf("exec: %v", err) + } + + b := bufio.NewReaderSize(out, 1<<20) + return b, nil +} + +// Wait waits for the command started with Run to exit. +func (ext *ExtDis) Wait() error { + return ext.Cmd.Wait() +} + +// testExtDis tests a set of byte sequences against an external disassembler. +// The disassembler is expected to produce the given syntax and run +// in the given architecture mode (16, 32, or 64-bit). +// The extdis function must start the external disassembler +// and then parse its output, sending the parsed instructions on ext.Dec. +// The generate function calls its argument f once for each byte sequence +// to be tested. The generate function itself will be called twice, and it must +// make the same sequence of calls to f each time. +// When a disassembly does not match the internal decoding, +// allowedMismatch determines whether this mismatch should be +// allowed, or else considered an error. +func testExtDis( + t *testing.T, + syntax string, + extdis func(ext *ExtDis) error, + generate func(f func([]byte)), + allowedMismatch func(text string, inst *Inst, dec ExtInst) bool, +) { + start := time.Now() + ext := &ExtDis{ + Dec: make(chan ExtInst), + } + errc := make(chan error) + + // First pass: write instructions to input file for external disassembler. + file, f, size, err := writeInst(generate) + if err != nil { + t.Fatal(err) + } + ext.Size = size + ext.File = f + defer func() { + f.Close() + if !*keep { + os.Remove(file) + } + }() + + // Second pass: compare disassembly against our decodings. + var ( + totalTests = 0 + totalSkips = 0 + totalErrors = 0 + + errors = make([]string, 0, 100) // Sampled errors, at most cap + ) + go func() { + errc <- extdis(ext) + }() + + generate(func(enc []byte) { + dec, ok := <-ext.Dec + if !ok { + t.Errorf("decoding stream ended early") + return + } + inst, text := disasm(syntax, pad(enc)) + + totalTests++ + if *dumpTest { + fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc) + } + + if text != dec.text && !strings.Contains(dec.text, "unknown") && syntax == "gnu" { + suffix := "" + if allowedMismatch(text, &inst, dec) { + totalSkips++ + if !*mismatch { + return + } + suffix += " (allowed mismatch)" + } + totalErrors++ + cmp := fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s\n", enc, text, len(enc), dec.text, dec.nenc, suffix) + + if len(errors) >= cap(errors) { + j := rand.Intn(totalErrors) + if j >= cap(errors) { + return + } + errors = append(errors[:j], errors[j+1:]...) + } + errors = append(errors, cmp) + } + }) + + if *mismatch { + totalErrors -= totalSkips + } + + fmt.Printf("totalTest: %d total skip: %d total error: %d\n", totalTests, totalSkips, totalErrors) + + // Here are some errors about mismatches(44) + for _, b := range errors { + t.Log(b) + } + + if totalErrors > 0 { + t.Fail() + } + t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds()) + t.Logf("decoder coverage: %.1f%%;\n", decodeCoverage()) +} + +// Start address of text. +const start = 0x8000 + +// writeInst writes the generated byte sequences to a new file +// starting at offset start. That file is intended to be the input to +// the external disassembler. +func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) { + f, err = ioutil.TempFile("", "loong64asm") + if err != nil { + return + } + + file = f.Name() + + f.Seek(start, io.SeekStart) + w := bufio.NewWriter(f) + defer w.Flush() + size = 0 + generate(func(x []byte) { + if debug { + fmt.Printf("%#x: %x%x\n", start+size, x, zeros[len(x):]) + } + w.Write(x) + w.Write(zeros[len(x):]) + size += len(zeros) + }) + return file, f, size, nil +} + +var zeros = []byte{0, 0, 0, 0} + +// pad pads the code sequence with pops. +func pad(enc []byte) []byte { + if len(enc) < 4 { + enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...) + } + return enc +} + +// disasm returns the decoded instruction and text +// for the given source bytes, using the given syntax and mode. +func disasm(syntax string, src []byte) (inst Inst, text string) { + var err error + inst, err = Decode(src) + if err != nil { + text = "error: " + err.Error() + return + } + text = inst.String() + switch syntax { + case "gnu": + text = GNUSyntax(inst) + case "plan9": // [sic] + text = GoSyntax(inst, 0, nil) + default: + text = "error: unknown syntax " + syntax + } + return +} + +// decodecoverage returns a floating point number denoting the +// decoder coverage. +func decodeCoverage() float64 { + n := 0 + for _, t := range decoderCover { + if t { + n++ + } + } + return 100 * float64(1+n) / float64(1+len(decoderCover)) +} + +// Helpers for writing disassembler output parsers. + +// isHex reports whether b is a hexadecimal character (0-9a-fA-F). +func isHex(b byte) bool { + return ('0' <= b && b <= '9') || ('a' <= b && b <= 'f') || ('A' <= b && b <= 'F') +} + +// parseHex parses the hexadecimal byte dump in hex, +// appending the parsed bytes to raw and returning the updated slice. +// The returned bool reports whether any invalid hex was found. +// Spaces and tabs between bytes are okay but any other non-hex is not. +func parseHex(hex []byte, raw []byte) ([]byte, bool) { + hex = bytes.TrimSpace(hex) + for j := 0; j < len(hex); { + for hex[j] == ' ' || hex[j] == '\t' { + j++ + } + if j >= len(hex) { + break + } + if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) { + return nil, false + } + raw = append(raw, unhex(hex[j])<<4|unhex(hex[j+1])) + j += 2 + } + return raw, true +} + +func unhex(b byte) byte { + if '0' <= b && b <= '9' { + return b - '0' + } else if 'A' <= b && b <= 'F' { + return b - 'A' + 10 + } else if 'a' <= b && b <= 'f' { + return b - 'a' + 10 + } + return 0 +} + +// index is like bytes.Index(s, []byte(t)) but avoids the allocation. +func index(s []byte, t string) int { + i := 0 + for { + j := bytes.IndexByte(s[i:], t[0]) + if j < 0 { + return -1 + } + i = i + j + if i+len(t) > len(s) { + return -1 + } + for k := 1; k < len(t); k++ { + if s[i+k] != t[k] { + goto nomatch + } + } + return i + nomatch: + i++ + } +} + +// fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s. +// If s must be rewritten, it is rewritten in place. +func fixSpace(s []byte) []byte { + s = bytes.TrimSpace(s) + for i := 0; i < len(s); i++ { + if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' { + goto Fix + } + } + return s + +Fix: + b := s + w := 0 + for i := 0; i < len(s); i++ { + c := s[i] + if c == '\t' || c == '\n' { + c = ' ' + } + if c == ' ' && w > 0 && b[w-1] == ' ' { + continue + } + b[w] = c + w++ + } + if w > 0 && b[w-1] == ' ' { + w-- + } + return b[:w] +} + +// Generators. +// +// The test cases are described as functions that invoke a callback repeatedly, +// with a new input sequence each time. These helpers make writing those +// a little easier. + +// hexCases generates the cases written in hexadecimal in the encoded string. +// Spaces in 'encoded' separate entire test cases, not individual bytes. +func hexCases(t *testing.T, encoded string) func(func([]byte)) { + return func(try func([]byte)) { + for _, x := range strings.Fields(encoded) { + src, err := hex.DecodeString(x) + if err != nil { + t.Errorf("parsing %q: %v", x, err) + } + try(src) + } + } +} + +// testdataCases generates the test cases recorded in testdata/cases.txt. +// It only uses the inputs; it ignores the answers recorded in that file. +func testdataCases(t *testing.T, syntax string) func(func([]byte)) { + var codes [][]byte + input := filepath.Join("testdata", syntax+"cases.txt") + data, err := ioutil.ReadFile(input) + if err != nil { + t.Fatal(err) + } + for _, line := range strings.Split(string(data), "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + f := strings.Fields(line)[0] + i := strings.Index(f, "|") + if i < 0 { + t.Errorf("parsing %q: missing | separator", f) + continue + } + if i%2 != 0 { + t.Errorf("parsing %q: misaligned | separator", f) + } + code, err := hex.DecodeString(f[:i] + f[i+1:]) + if err != nil { + t.Errorf("parsing %q: %v", f, err) + continue + } + codes = append(codes, code) + } + + return func(try func([]byte)) { + for _, code := range codes { + try(code) + } + } +}
diff --git a/loong64/loong64asm/gnu.go b/loong64/loong64asm/gnu.go new file mode 100644 index 0000000..4807abc --- /dev/null +++ b/loong64/loong64asm/gnu.go
@@ -0,0 +1,16 @@ +// 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 ( + "strings" +) + +// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils. +// This form typically matches the syntax defined in the Loong64 Reference Manual. See +// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html +func GNUSyntax(inst Inst) string { + return strings.ToLower(inst.String()) +}
diff --git a/loong64/loong64asm/inst.go b/loong64/loong64asm/inst.go new file mode 100644 index 0000000..1ac5c79 --- /dev/null +++ b/loong64/loong64asm/inst.go
@@ -0,0 +1,298 @@ +// 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[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)) +}
diff --git a/loong64/loong64asm/objdump_test.go b/loong64/loong64asm/objdump_test.go new file mode 100644 index 0000000..0476655 --- /dev/null +++ b/loong64/loong64asm/objdump_test.go
@@ -0,0 +1,145 @@ +// 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 ( + "strconv" + "strings" + "testing" +) + +func TestObjdumpLoong64TestDecodeGNUSyntaxdata(t *testing.T) { + testObjdumpLoong64(t, testdataCases(t, "gnu")) +} + +func TestObjdumpLoong64TestDecodeGoSyntaxdata(t *testing.T) { + testObjdumpLoong64(t, testdataCases(t, "plan9")) +} + +func TestObjdumpLoong64Manual(t *testing.T) { + testObjdumpLoong64(t, hexCases(t, objdumpManualTests)) +} + +// objdumpManualTests holds test cases that will be run by TestObjdumpLoong64Manual. +// If you are debugging a few cases that turned up in a longer run, it can be useful +// to list them here and then use -run=Manual, particularly with tracing enabled. +// Note that these are byte sequences, so they must be reversed from the usual +// word presentation. +var objdumpManualTests = ` +00007238 +00807238 +00004003 +00100050 +ac410028 +ac41002a +ac41c028 +ac414028 +ac41402a +ac418028 +ac41802a +ac397838 +acb97938 +acb97838 +ac397938 +ac397a38 +acb97b38 +acb97a38 +ac397b38 +ac110026 +ac110024 +ac390038 +ac392038 +ac390c38 +ac390438 +ac392438 +ac390838 +ac392838 +ac391600 +ac391400 +ac391500 +ac418003 +` + +// allowedMismatchObjdump reports whether the mismatch between text and dec +// should be allowed by the test. +func allowedMismatchObjdump(text string, inst *Inst, dec ExtInst) bool { + // GNU objdump use register, decode use alias of register, so corrected it in here + var dec_text = strings.Replace(dec.text, " ", ",", -1) + var decsp []string = strings.Split(dec_text, ",") + var num int = cap(decsp) + for i := 0; i < num; i++ { + dex := strings.Index(decsp[i], "$r") + fdex := strings.Index(decsp[i], "$f") + ddex := strings.Index(decsp[i], "(") + if ddex > 0 { + // ldptr.w $r12,$r13,16(0x10) + decsp[i] = decsp[i][0:ddex] + } + xdex := strings.Index(decsp[i], "0x") + // convert registers to registers aliases + if dex >= 0 { + reg, _ := strconv.Atoi(decsp[i][dex+2:]) + // r12~r20 $t0~t8 + if reg >= 12 && reg <= 20 { + decsp[i] = strings.Join([]string{"t", strconv.Itoa(reg - 12)}, "") + } + // r4~r11 $a0~a7 + if reg >= 4 && reg <= 11 { + decsp[i] = strings.Join([]string{"a", strconv.Itoa(reg - 4)}, "") + } + // r23~r31 $s0~s8 + if reg >= 23 && reg <= 31 { + decsp[i] = strings.Join([]string{"s", strconv.Itoa(reg - 23)}, "") + } + // r0 zero + if reg == 0 { + decsp[i] = strings.Join([]string{"zero"}, "") + } + // r1 ra + if reg == 1 { + decsp[i] = strings.Join([]string{"ra"}, "") + } + // r2 tp + if reg == 2 { + decsp[i] = strings.Join([]string{"tp"}, "") + } + // r3 sp + if reg == 3 { + decsp[i] = strings.Join([]string{"sp"}, "") + } + // r21 x + if reg == 21 { + decsp[i] = strings.Join([]string{"x"}, "") + } + // r22 fp + if reg == 22 { + decsp[i] = strings.Join([]string{"fp"}, "") + } + } + // convert hexadecimal to decimal + if xdex >= 0 { + parseint, _ := strconv.ParseInt(decsp[i][xdex+2:], 16, 32) + decsp[i] = strings.Join([]string{strconv.Itoa(int(parseint))}, "") + } + // convert floating-point registers to floating-point aliases + if fdex >= 0 && !strings.Contains(decsp[i], "$fcc") { + freg, _ := strconv.Atoi(decsp[i][fdex+2:]) + // f0~f7 fa0~fa7 + if freg >= 0 && freg <= 7 { + decsp[i] = strings.Join([]string{"fa", strconv.Itoa(freg - 0)}, "") + } + // f8~f23 ft0~ft15 + if freg >= 8 && freg <= 23 { + decsp[i] = strings.Join([]string{"ft", strconv.Itoa(freg - 8)}, "") + } + // f24~f31 fs0~fs7 + if freg >= 24 && freg <= 31 { + decsp[i] = strings.Join([]string{"fs", strconv.Itoa(freg - 24)}, "") + } + } + } + + return false +}
diff --git a/loong64/loong64asm/objdumpext_test.go b/loong64/loong64asm/objdumpext_test.go new file mode 100644 index 0000000..80396d9 --- /dev/null +++ b/loong64/loong64asm/objdumpext_test.go
@@ -0,0 +1,249 @@ +// 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 ( + "bytes" + "debug/elf" + "encoding/binary" + "fmt" + "io" + "log" + "os" + "os/exec" + "strconv" + "strings" + "testing" +) + +const objdumpPath = "/usr/bin/objdump" + +func testObjdumpLoong64(t *testing.T, generate func(func([]byte))) { + testObjdumpArch(t, generate) +} + +func testObjdumpArch(t *testing.T, generate func(func([]byte))) { + checkObjdumpLoong64(t) + testExtDis(t, "gnu", objdump, generate, allowedMismatchObjdump) + testExtDis(t, "plan9", objdump, generate, allowedMismatchObjdump) +} + +func checkObjdumpLoong64(t *testing.T) { + out, err := exec.Command(objdumpPath, "-i").Output() + if err != nil { + t.Skipf("cannot run objdump: %v\n%s", err, out) + } + if !strings.Contains(string(out), "Loongarch64") { + t.Skip("objdump does not have loong64 support") + } +} + +func objdump(ext *ExtDis) error { + // File already written with instructions; add ELF header. + if err := writeELF64(ext.File, ext.Size); err != nil { + return err + } + + b, err := ext.Run(objdumpPath, "-d", "-z", ext.File.Name()) + if err != nil { + return err + } + + var ( + nmatch int + reading bool + next uint64 = start + addr uint64 + encbuf [4]byte + enc []byte + text string + ) + flush := func() { + if addr == next { + // PC-relative addresses are translated to absolute addresses based on PC by GNU objdump + // Following logical rewrites the absolute addresses back to PC-relative ones for comparing + // with our disassembler output which are PC-relative + if text == "undefined" && len(enc) == 4 { + text = "error: unknown instruction" + enc = nil + } + if len(enc) == 4 { + // prints as word but we want to record bytes + enc[0], enc[3] = enc[3], enc[0] + enc[1], enc[2] = enc[2], enc[1] + } + ext.Dec <- ExtInst{addr, encbuf, len(enc), text} + encbuf = [4]byte{} + enc = nil + next += 4 + } + } + var textangle = []byte("<.text>:") + for { + line, err := b.ReadSlice('\n') + if err != nil { + if err == io.EOF { + break + } + return fmt.Errorf("reading objdump output: %v", err) + } + if bytes.Contains(line, textangle) { + reading = true + continue + } + if !reading { + continue + } + if debug { + os.Stdout.Write(line) + } + if enc1 := parseContinuation(line, encbuf[:len(enc)]); enc1 != nil { + enc = enc1 + continue + } + flush() + nmatch++ + addr, enc, text = parseLine(line, encbuf[:0]) + if addr > next { + return fmt.Errorf("address out of sync expected <= %#x at %q in:\n%s", next, line, line) + } + } + flush() + if next != start+uint64(ext.Size) { + return fmt.Errorf("not enough results found [%d %d]", next, start+ext.Size) + } + if err := ext.Wait(); err != nil { + return fmt.Errorf("exec: %v", err) + } + + return nil +} + +var ( + undefined = []byte("undefined") + unpredictable = []byte("unpredictable") + slashslash = []byte("//") +) + +func parseLine(line []byte, encstart []byte) (addr uint64, enc []byte, text string) { + ok := false + oline := line + i := index(line, ":\t") + if i < 0 { + log.Fatalf("cannot parse disassembly: %q", oline) + } + x, err := strconv.ParseUint(string(bytes.TrimSpace(line[:i])), 16, 32) + if err != nil { + log.Fatalf("cannot parse disassembly: %q", oline) + } + addr = uint64(x) + line = line[i+2:] + i = bytes.IndexByte(line, '\t') + if i < 0 { + log.Fatalf("cannot parse disassembly: %q", oline) + } + enc, ok = parseHex(line[:i], encstart) + if !ok { + log.Fatalf("cannot parse disassembly: %q", oline) + } + line = bytes.TrimSpace(line[i:]) + if bytes.Contains(line, undefined) { + text = "undefined" + return + } + if false && bytes.Contains(line, unpredictable) { + text = "unpredictable" + return + } + // Strip trailing comment starting with '#' + if i := bytes.IndexByte(line, '#'); i >= 0 { + line = bytes.TrimSpace(line[:i]) + } + // Strip trailing comment starting with "//" + if i := bytes.Index(line, slashslash); i >= 0 { + line = bytes.TrimSpace(line[:i]) + } + text = string(fixSpace(line)) + return +} + +func parseContinuation(line []byte, enc []byte) []byte { + i := index(line, ":\t") + if i < 0 { + return nil + } + line = line[i+1:] + enc, _ = parseHex(line, enc) + return enc +} + +// writeELF64 writes an ELF64 header to the file, describing a text +// segment that starts at start (0x8000) and extends for size bytes. +func writeELF64(f *os.File, size int) error { + f.Seek(0, io.SeekStart) + var hdr elf.Header64 + var prog elf.Prog64 + var sect elf.Section64 + var buf bytes.Buffer + binary.Write(&buf, binary.LittleEndian, &hdr) + off1 := buf.Len() + binary.Write(&buf, binary.LittleEndian, &prog) + off2 := buf.Len() + binary.Write(&buf, binary.LittleEndian, §) + off3 := buf.Len() + buf.Reset() + data := byte(elf.ELFDATA2LSB) + hdr = elf.Header64{ + Ident: [16]byte{0x7F, 'E', 'L', 'F', 2, data, 1}, + Type: 2, + Machine: uint16(elf.EM_LOONGARCH), + Version: 1, + Entry: start, + Phoff: uint64(off1), + Shoff: uint64(off2), + Flags: 0x3, + Ehsize: uint16(off1), + Phentsize: uint16(off2 - off1), + Phnum: 1, + Shentsize: uint16(off3 - off2), + Shnum: 3, + Shstrndx: 2, + } + binary.Write(&buf, binary.LittleEndian, &hdr) + prog = elf.Prog64{ + Type: 1, + Off: start, + Vaddr: start, + Paddr: start, + Filesz: uint64(size), + Memsz: uint64(size), + Flags: 5, + Align: start, + } + binary.Write(&buf, binary.LittleEndian, &prog) + binary.Write(&buf, binary.LittleEndian, §) // NULL section + sect = elf.Section64{ + Name: 1, + Type: uint32(elf.SHT_PROGBITS), + Addr: start, + Off: start, + Size: uint64(size), + Flags: uint64(elf.SHF_ALLOC | elf.SHF_EXECINSTR), + Addralign: 4, + } + binary.Write(&buf, binary.LittleEndian, §) // .text + sect = elf.Section64{ + Name: uint32(len("\x00.text\x00")), + Type: uint32(elf.SHT_STRTAB), + Addr: 0, + Off: uint64(off2 + (off3-off2)*3), + Size: uint64(len("\x00.text\x00.shstrtab\x00")), + Addralign: 1, + } + binary.Write(&buf, binary.LittleEndian, §) + buf.WriteString("\x00.text\x00.shstrtab\x00") + f.Write(buf.Bytes()) + return nil +}
diff --git a/loong64/loong64asm/plan9x.go b/loong64/loong64asm/plan9x.go new file mode 100644 index 0000000..5db3290 --- /dev/null +++ b/loong64/loong64asm/plan9x.go
@@ -0,0 +1,536 @@ +// 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" +) + +// GoSyntax returns the Go assembler syntax for the instruction. +// The syntax was originally defined by Plan 9. +// The pc is the program counter of the instruction, used for +// expanding PC-relative addresses into absolute ones. +// The symname function queries the symbol table for the program +// being disassembled. Given a target address it returns the name +// and base address of the symbol containing the target, if any; +// otherwise it returns "", 0. +func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string { + if symname == nil { + symname = func(uint64) (string, uint64) { return "", 0 } + } + if inst.Op == 0 && inst.Enc == 0 { + return "WORD $0" + } else if inst.Op == 0 { + return "?" + } + + var args []string + for _, a := range inst.Args { + if a == nil { + break + } + args = append(args, plan9Arg(&inst, pc, symname, a)) + } + + var op string = plan9OpMap[inst.Op] + if op == "" { + op = "Unknown " + inst.Op.String() + } + + switch inst.Op { + case BSTRPICK_W, BSTRPICK_D, BSTRINS_W, BSTRINS_D: + msbw, lsbw := inst.Args[2].(Uimm), inst.Args[3].(Uimm) + if inst.Op == BSTRPICK_D && msbw.Imm == 15 && lsbw.Imm == 0 { + op = "MOVHU" + args = append(args[1:2], args[0:1]...) + } else { + args[0], args[1], args[2], args[3] = args[2], args[1], args[3], args[0] + } + + case BCNEZ, BCEQZ: + args = args[1:2] + + case BEQ, BNE: + rj := inst.Args[0].(Reg) + rd := inst.Args[1].(Reg) + if rj == rd && inst.Op == BEQ { + op = "JMP" + args = args[2:] + } else if rj == R0 { + args = args[1:] + } else if rd == R0 { + args = append(args[:1], args[2:]...) + } + + case BEQZ, BNEZ: + if inst.Args[0].(Reg) == R0 && inst.Op == BEQ { + op = "JMP" + args = args[1:] + } + + case BLT, BLTU, BGE, BGEU: + rj := inst.Args[0].(Reg) + rd := inst.Args[1].(Reg) + if rj == rd && (inst.Op == BGE || inst.Op == BGEU) { + op = "JMP" + args = args[2:] + } else if rj == R0 { + switch inst.Op { + case BGE: + op = "BLEZ" + case BLT: + op = "BGTZ" + } + args = args[1:] + } else if rd == R0 { + if !strings.HasSuffix(op, "U") { + op += "Z" + } + args = append(args[:1], args[2:]...) + } + + case JIRL: + rd := inst.Args[0].(Reg) + rj := inst.Args[1].(Reg) + regno := uint16(rj) & 31 + if rd == R0 { + return fmt.Sprintf("JMP (R%d)", regno) + } + return fmt.Sprintf("CALL (R%d)", regno) + + case LD_B, LD_H, LD_W, LD_D, LD_BU, LD_HU, LD_WU, LL_W, LL_D, + ST_B, ST_H, ST_W, ST_D, SC_W, SC_D, FLD_S, FLD_D, FST_S, FST_D: + var off int32 + switch a := inst.Args[2].(type) { + case Simm16: + off = signumConvInt32(int32(a.Imm), a.Width) + case Simm32: + off = signumConvInt32(int32(a.Imm), a.Width) >> 2 + } + Iop := strings.ToUpper(inst.Op.String()) + if strings.HasPrefix(Iop, "L") || strings.HasPrefix(Iop, "FL") { + return fmt.Sprintf("%s %d(%s), %s", op, off, args[1], args[0]) + } + return fmt.Sprintf("%s %s, %d(%s)", op, args[0], off, args[1]) + + case LDX_B, LDX_H, LDX_W, LDX_D, LDX_BU, LDX_HU, LDX_WU, FLDX_S, FLDX_D, + STX_B, STX_H, STX_W, STX_D, FSTX_S, FSTX_D: + Iop := strings.ToUpper(inst.Op.String()) + if strings.HasPrefix(Iop, "L") || strings.HasPrefix(Iop, "FL") { + return fmt.Sprintf("%s (%s)(%s), %s", op, args[1], args[2], args[0]) + } + return fmt.Sprintf("%s %s, (%s)(%s)", op, args[0], args[1], args[2]) + + case AMADD_B, AMADD_D, AMADD_DB_B, AMADD_DB_D, AMADD_DB_H, AMADD_DB_W, AMADD_H, + AMADD_W, AMAND_D, AMAND_DB_D, AMAND_DB_W, AMAND_W, AMCAS_B, AMCAS_D, AMCAS_DB_B, + AMCAS_DB_D, AMCAS_DB_H, AMCAS_DB_W, AMCAS_H, AMCAS_W, AMMAX_D, AMMAX_DB_D, + AMMAX_DB_DU, AMMAX_DB_W, AMMAX_DB_WU, AMMAX_DU, AMMAX_W, AMMAX_WU, AMMIN_D, + AMMIN_DB_D, AMMIN_DB_DU, AMMIN_DB_W, AMMIN_DB_WU, AMMIN_DU, AMMIN_W, AMMIN_WU, + AMOR_D, AMOR_DB_D, AMOR_DB_W, AMOR_W, AMSWAP_B, AMSWAP_D, AMSWAP_DB_B, AMSWAP_DB_D, + AMSWAP_DB_H, AMSWAP_DB_W, AMSWAP_H, AMSWAP_W, AMXOR_D, AMXOR_DB_D, AMXOR_DB_W, AMXOR_W: + return fmt.Sprintf("%s %s, (%s), %s", op, args[1], args[2], args[0]) + + default: + // Reverse args, placing dest last + for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 { + args[i], args[j] = args[j], args[i] + } + switch len(args) { // Special use cases + case 0, 1: + if inst.Op != B && inst.Op != BL { + return op + } + + case 3: + switch a0 := inst.Args[0].(type) { + case Reg: + rj := inst.Args[1].(Reg) + if a0 == rj && a0 != R0 { + args = args[0:2] + } + } + switch inst.Op { + case SUB_W, SUB_D, ADDI_W, ADDI_D, ORI: + rj := inst.Args[1].(Reg) + if rj == R0 { + args = append(args[0:1], args[2:]...) + if inst.Op == SUB_W { + op = "NEGW" + } else if inst.Op == SUB_D { + op = "NEGV" + } else { + op = "MOVW" + } + } + + case ANDI: + ui12 := inst.Args[2].(Uimm) + if ui12.Imm == uint32(0xff) { + op = "MOVBU" + args = args[1:] + } else if ui12.Imm == 0 && inst.Args[0].(Reg) == R0 && inst.Args[1].(Reg) == R0 { + return "NOOP" + } + + case SLL_W, OR: + rk := inst.Args[2].(Reg) + if rk == R0 { + args = args[1:] + if inst.Op == SLL_W { + op = "MOVW" + } else { + op = "MOVV" + } + } + } + } + } + + if args != nil { + op += " " + strings.Join(args, ", ") + } + return op +} + +func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string { + // Reg: gpr[0, 31] and fpr[0, 31] + // Fcsr: fcsr[0, 3] + // Fcc: fcc[0, 7] + // Uimm: unsigned integer constant + // Simm16: si16 + // Simm32: si32 + // OffsetSimm: si32 + switch a := arg.(type) { + case Reg: + regenum := uint16(a) + regno := uint16(a) & 0x1f + // General-purpose register + if regenum >= uint16(R0) && regenum <= uint16(R31) { + return fmt.Sprintf("R%d", regno) + } else { // Float point register + return fmt.Sprintf("F%d", regno) + } + + case Fcsr: + regno := uint8(a) & 0x1f + return fmt.Sprintf("FCSR%d", regno) + + case Fcc: + regno := uint8(a) & 0x1f + return fmt.Sprintf("FCC%d", regno) + + case Uimm: + return fmt.Sprintf("$%d", a.Imm) + + case Simm16: + si16 := signumConvInt32(int32(a.Imm), a.Width) + return fmt.Sprintf("$%d", si16) + + case Simm32: + si32 := signumConvInt32(a.Imm, a.Width) + return fmt.Sprintf("$%d", si32) + + case OffsetSimm: + offs := offsConvInt32(a.Imm, a.Width) + if inst.Op == B || inst.Op == BL { + addr := int64(pc) + int64(a.Imm) + if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base { + return fmt.Sprintf("%s(SB)", s) + } + } + return fmt.Sprintf("%d(PC)", offs>>2) + + case SaSimm: + return fmt.Sprintf("$%d", a) + + case CodeSimm: + return fmt.Sprintf("$%d", a) + + } + return strings.ToUpper(arg.String()) +} + +func signumConvInt32(imm int32, width uint8) int32 { + active := uint32(1<<width) - 1 + signum := uint32(imm) & active + if ((signum >> (width - 1)) & 0x1) == 1 { + signum |= ^active + } + return int32(signum) +} + +func offsConvInt32(imm int32, width uint8) int32 { + relWidth := width + 2 + return signumConvInt32(imm, relWidth) +} + +var plan9OpMap = map[Op]string{ + ADD_W: "ADD", + ADD_D: "ADDV", + SUB_W: "SUB", + SUB_D: "SUBV", + ADDI_W: "ADD", + ADDI_D: "ADDV", + LU12I_W: "LU12IW", + LU32I_D: "LU32ID", + LU52I_D: "LU52ID", + SLT: "SGT", + SLTU: "SGTU", + SLTI: "SGT", + SLTUI: "SGTU", + PCADDU12I: "PCADDU12I", + PCALAU12I: "PCALAU12I", + AND: "AND", + OR: "OR", + NOR: "NOR", + XOR: "XOR", + ANDI: "AND", + ORI: "OR", + XORI: "XOR", + MUL_W: "MUL", + MULH_W: "MULH", + MULH_WU: "MULHU", + MUL_D: "MULV", + MULH_D: "MULHV", + MULH_DU: "MULHVU", + DIV_W: "DIV", + DIV_WU: "DIVU", + DIV_D: "DIVV", + DIV_DU: "DIVVU", + MOD_W: "REM", + MOD_WU: "REMU", + MOD_D: "REMV", + MOD_DU: "REMVU", + SLL_W: "SLL", + SRL_W: "SRL", + SRA_W: "SRA", + ROTR_W: "ROTR", + SLL_D: "SLLV", + SRL_D: "SRLV", + SRA_D: "SRAV", + ROTR_D: "ROTRV", + SLLI_W: "SLL", + SRLI_W: "SRL", + SRAI_W: "SRA", + ROTRI_W: "ROTR", + SLLI_D: "SLLV", + SRLI_D: "SRLV", + SRAI_D: "SRAV", + ROTRI_D: "ROTRV", + EXT_W_B: "?", + EXT_W_H: "?", + BITREV_W: "BITREVW", + BITREV_D: "BITREVV", + CLO_W: "CLOW", + CLO_D: "CLOV", + CLZ_W: "CLZW", + CLZ_D: "CLZV", + CTO_W: "CTOW", + CTO_D: "CTOV", + CTZ_W: "CTZW", + CTZ_D: "CTZV", + REVB_2H: "REVB2H", + REVB_2W: "REVB2W", + REVB_4H: "REVB4H", + REVB_D: "REVBV", + BSTRPICK_W: "BSTRPICKW", + BSTRPICK_D: "BSTRPICKV", + BSTRINS_W: "BSTRINSW", + BSTRINS_D: "BSTRINSV", + MASKEQZ: "MASKEQZ", + MASKNEZ: "MASKNEZ", + BCNEZ: "BFPT", + BCEQZ: "BFPF", + BEQ: "BEQ", + BNE: "BNE", + BEQZ: "BEQ", + BNEZ: "BNE", + BLT: "BLT", + BLTU: "BLTU", + BGE: "BGE", + BGEU: "BGEU", + B: "JMP", + BL: "CALL", + LD_B: "MOVB", + LD_H: "MOVH", + LD_W: "MOVW", + LD_D: "MOVV", + LD_BU: "MOVBU", + LD_HU: "MOVHU", + LD_WU: "MOVWU", + ST_B: "MOVB", + ST_H: "MOVH", + ST_W: "MOVW", + ST_D: "MOVV", + LDX_B: "MOVB", + LDX_BU: "MOVBU", + LDX_D: "MOVV", + LDX_H: "MOVH", + LDX_HU: "MOVHU", + LDX_W: "MOVW", + LDX_WU: "MOVWU", + STX_B: "MOVB", + STX_D: "MOVV", + STX_H: "MOVH", + STX_W: "MOVW", + AMADD_B: "AMADDB", + AMADD_D: "AMADDV", + AMADD_DB_B: "AMADDDBB", + AMADD_DB_D: "AMADDDBV", + AMADD_DB_H: "AMADDDBH", + AMADD_DB_W: "AMADDDBW", + AMADD_H: "AMADDH", + AMADD_W: "AMADDW", + AMAND_D: "AMANDV", + AMAND_DB_D: "AMANDDBV", + AMAND_DB_W: "AMANDDBW", + AMAND_W: "AMANDW", + AMCAS_B: "AMCASB", + AMCAS_D: "AMCASV", + AMCAS_DB_B: "AMCASDBB", + AMCAS_DB_D: "AMCASDBV", + AMCAS_DB_H: "AMCASDBH", + AMCAS_DB_W: "AMCASDBW", + AMCAS_H: "AMCASH", + AMCAS_W: "AMCASW", + AMMAX_D: "AMMAXV", + AMMAX_DB_D: "AMMAXDBV", + AMMAX_DB_DU: "AMMAXDBVU", + AMMAX_DB_W: "AMMAXDBW", + AMMAX_DB_WU: "AMMAXDBWU", + AMMAX_DU: "AMMAXVU", + AMMAX_W: "AMMAXW", + AMMAX_WU: "AMMAXWU", + AMMIN_D: "AMMINV", + AMMIN_DB_D: "AMMINDBV", + AMMIN_DB_DU: "AMMINDBVU", + AMMIN_DB_W: "AMMINDBW", + AMMIN_DB_WU: "AMMINDBWU", + AMMIN_DU: "AMMINVU", + AMMIN_W: "AMMINW", + AMMIN_WU: "AMMINWU", + AMOR_D: "AMORV", + AMOR_DB_D: "AMORDBV", + AMOR_DB_W: "AMORDBW", + AMOR_W: "AMORW", + AMSWAP_B: "AMSWAPB", + AMSWAP_D: "AMSWAPV", + AMSWAP_DB_B: "AMSWAPDBB", + AMSWAP_DB_D: "AMSWAPDBV", + AMSWAP_DB_H: "AMSWAPDBH", + AMSWAP_DB_W: "AMSWAPDBW", + AMSWAP_H: "AMSWAPH", + AMSWAP_W: "AMSWAPW", + AMXOR_D: "AMXORV", + AMXOR_DB_D: "AMXORDBV", + AMXOR_DB_W: "AMXORDBW", + AMXOR_W: "AMXORW", + LL_W: "LL", + LL_D: "LLV", + SC_W: "SC", + SC_D: "SCV", + CRCC_W_B_W: "CRCCWBW", + CRCC_W_D_W: "CRCCWVW", + CRCC_W_H_W: "CRCCWHW", + CRCC_W_W_W: "CRCCWWW", + CRC_W_B_W: "CRCWBW", + CRC_W_D_W: "CRCWVW", + CRC_W_H_W: "CRCWHW", + CRC_W_W_W: "CRCWWW", + DBAR: "DBAR", + SYSCALL: "SYSCALL", + BREAK: "BREAK", + RDTIMEL_W: "RDTIMELW", + RDTIMEH_W: "RDTIMEHW", + RDTIME_D: "RDTIMED", + CPUCFG: "CPUCFG", + + // Floating-point instructions + FADD_S: "ADDF", + FADD_D: "ADDD", + FSUB_S: "SUBF", + FSUB_D: "SUBD", + FMUL_S: "MULF", + FMUL_D: "MULD", + FDIV_S: "DIVF", + FDIV_D: "DIVD", + FMSUB_S: "FMSUBF", + FMSUB_D: "FMSUBD", + FMADD_S: "FMADDF", + FMADD_D: "FMADDD", + FNMADD_S: "FNMADDF", + FNMADD_D: "FNMADDD", + FNMSUB_S: "FNMSUBF", + FNMSUB_D: "FNMSUBD", + FABS_S: "ABSF", + FABS_D: "ABSD", + FNEG_S: "NEGF", + FNEG_D: "NEGD", + FSQRT_S: "SQRTF", + FSQRT_D: "SQRTD", + FCOPYSIGN_S: "FCOPYSGF", + FCOPYSIGN_D: "FCOPYSGD", + FMAX_S: "FMAXF", + FMAX_D: "FMAXD", + FMIN_S: "FMINF", + FMIN_D: "FMIND", + FCLASS_S: "FCLASSF", + FCLASS_D: "FCLASSD", + FCMP_CEQ_S: "CMPEQF", + FCMP_CEQ_D: "CMPEQD", + FCMP_SLE_S: "CMPGEF", + FCMP_SLE_D: "CMPGED", + FCMP_SLT_S: "CMPGTF", + FCMP_SLT_D: "CMPGTD", + FCVT_D_S: "MOVFD", + FCVT_S_D: "MOVDF", + FFINT_S_W: "FFINTFW", + FFINT_S_L: "FFINTFV", + FFINT_D_W: "FFINTDW", + FFINT_D_L: "FFINTDV", + FTINTRM_L_D: "FTINTRMVD", + FTINTRM_L_S: "FTINTRMVF", + FTINTRM_W_D: "FTINTRMWD", + FTINTRM_W_S: "FTINTRMWF", + FTINTRNE_L_D: "FTINTRNEVD", + FTINTRNE_L_S: "FTINTRNEVF", + FTINTRNE_W_D: "FTINTRNEWD", + FTINTRNE_W_S: "FTINTRNEWF", + FTINTRP_L_D: "FTINTRPVD", + FTINTRP_L_S: "FTINTRPVF", + FTINTRP_W_D: "FTINTRPWD", + FTINTRP_W_S: "FTINTRPWF", + FTINTRZ_L_D: "FTINTRZVD", + FTINTRZ_L_S: "FTINTRZVF", + FTINTRZ_W_D: "FTINTRZWD", + FTINTRZ_W_S: "FTINTRZWF", + FTINT_L_D: "FTINTVD", + FTINT_L_S: "FTINTVF", + FTINT_W_D: "FTINTWD", + FTINT_W_S: "FTINTWF", + FRINT_S: "FRINTS", + FRINT_D: "FRINTD", + FMOV_S: "MOVF", + FMOV_D: "MOVD", + MOVGR2FR_W: "MOVW", + MOVGR2FR_D: "MOVV", + MOVFR2GR_S: "MOVW", + MOVFR2GR_D: "MOVV", + MOVGR2CF: "MOVV", + MOVCF2GR: "MOVV", + MOVFCSR2GR: "MOVV", + MOVGR2FCSR: "MOVV", + MOVFR2CF: "MOVV", + MOVCF2FR: "MOVV", + FLD_S: "MOVF", + FLD_D: "MOVD", + FST_S: "MOVF", + FST_D: "MOVD", + FLDX_S: "MOVF", + FLDX_D: "MOVD", + FSTX_S: "MOVF", + FSTX_D: "MOVD", +}
diff --git a/loong64/loong64asm/tables.go b/loong64/loong64asm/tables.go new file mode 100644 index 0000000..c85d47c --- /dev/null +++ b/loong64/loong64asm/tables.go
@@ -0,0 +1,1613 @@ +// Generated by loong64spec LoongArch-Vol1-EN.pdf, DO NOT EDIT. + +// 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 + +const ( + _ Op = iota + ADDI_D + ADDI_W + ADDU16I_D + ADD_D + ADD_W + ALSL_D + ALSL_W + ALSL_WU + AMADD_B + AMADD_D + AMADD_DB_B + AMADD_DB_D + AMADD_DB_H + AMADD_DB_W + AMADD_H + AMADD_W + AMAND_D + AMAND_DB_D + AMAND_DB_W + AMAND_W + AMCAS_B + AMCAS_D + AMCAS_DB_B + AMCAS_DB_D + AMCAS_DB_H + AMCAS_DB_W + AMCAS_H + AMCAS_W + AMMAX_D + AMMAX_DB_D + AMMAX_DB_DU + AMMAX_DB_W + AMMAX_DB_WU + AMMAX_DU + AMMAX_W + AMMAX_WU + AMMIN_D + AMMIN_DB_D + AMMIN_DB_DU + AMMIN_DB_W + AMMIN_DB_WU + AMMIN_DU + AMMIN_W + AMMIN_WU + AMOR_D + AMOR_DB_D + AMOR_DB_W + AMOR_W + AMSWAP_B + AMSWAP_D + AMSWAP_DB_B + AMSWAP_DB_D + AMSWAP_DB_H + AMSWAP_DB_W + AMSWAP_H + AMSWAP_W + AMXOR_D + AMXOR_DB_D + AMXOR_DB_W + AMXOR_W + AND + ANDI + ANDN + ASRTGT_D + ASRTLE_D + B + BCEQZ + BCNEZ + BEQ + BEQZ + BGE + BGEU + BITREV_4B + BITREV_8B + BITREV_D + BITREV_W + BL + BLT + BLTU + BNE + BNEZ + BREAK + BSTRINS_D + BSTRINS_W + BSTRPICK_D + BSTRPICK_W + BYTEPICK_D + BYTEPICK_W + CACOP + CLO_D + CLO_W + CLZ_D + CLZ_W + CPUCFG + CRCC_W_B_W + CRCC_W_D_W + CRCC_W_H_W + CRCC_W_W_W + CRC_W_B_W + CRC_W_D_W + CRC_W_H_W + CRC_W_W_W + CSRRD + CSRWR + CSRXCHG + CTO_D + CTO_W + CTZ_D + CTZ_W + DBAR + DBCL + DIV_D + DIV_DU + DIV_W + DIV_WU + ERTN + EXT_W_B + EXT_W_H + FABS_D + FABS_S + FADD_D + FADD_S + FCLASS_D + FCLASS_S + FCMP_CAF_D + FCMP_CAF_S + FCMP_CEQ_D + FCMP_CEQ_S + FCMP_CLE_D + FCMP_CLE_S + FCMP_CLT_D + FCMP_CLT_S + FCMP_CNE_D + FCMP_CNE_S + FCMP_COR_D + FCMP_COR_S + FCMP_CUEQ_D + FCMP_CUEQ_S + FCMP_CULE_D + FCMP_CULE_S + FCMP_CULT_D + FCMP_CULT_S + FCMP_CUNE_D + FCMP_CUNE_S + FCMP_CUN_D + FCMP_CUN_S + FCMP_SAF_D + FCMP_SAF_S + FCMP_SEQ_D + FCMP_SEQ_S + FCMP_SLE_D + FCMP_SLE_S + FCMP_SLT_D + FCMP_SLT_S + FCMP_SNE_D + FCMP_SNE_S + FCMP_SOR_D + FCMP_SOR_S + FCMP_SUEQ_D + FCMP_SUEQ_S + FCMP_SULE_D + FCMP_SULE_S + FCMP_SULT_D + FCMP_SULT_S + FCMP_SUNE_D + FCMP_SUNE_S + FCMP_SUN_D + FCMP_SUN_S + FCOPYSIGN_D + FCOPYSIGN_S + FCVT_D_S + FCVT_S_D + FDIV_D + FDIV_S + FFINT_D_L + FFINT_D_W + FFINT_S_L + FFINT_S_W + FLDGT_D + FLDGT_S + FLDLE_D + FLDLE_S + FLDX_D + FLDX_S + FLD_D + FLD_S + FLOGB_D + FLOGB_S + FMADD_D + FMADD_S + FMAXA_D + FMAXA_S + FMAX_D + FMAX_S + FMINA_D + FMINA_S + FMIN_D + FMIN_S + FMOV_D + FMOV_S + FMSUB_D + FMSUB_S + FMUL_D + FMUL_S + FNEG_D + FNEG_S + FNMADD_D + FNMADD_S + FNMSUB_D + FNMSUB_S + FRECIPE_D + FRECIPE_S + FRECIP_D + FRECIP_S + FRINT_D + FRINT_S + FRSQRTE_D + FRSQRTE_S + FRSQRT_D + FRSQRT_S + FSCALEB_D + FSCALEB_S + FSEL + FSQRT_D + FSQRT_S + FSTGT_D + FSTGT_S + FSTLE_D + FSTLE_S + FSTX_D + FSTX_S + FST_D + FST_S + FSUB_D + FSUB_S + FTINTRM_L_D + FTINTRM_L_S + FTINTRM_W_D + FTINTRM_W_S + FTINTRNE_L_D + FTINTRNE_L_S + FTINTRNE_W_D + FTINTRNE_W_S + FTINTRP_L_D + FTINTRP_L_S + FTINTRP_W_D + FTINTRP_W_S + FTINTRZ_L_D + FTINTRZ_L_S + FTINTRZ_W_D + FTINTRZ_W_S + FTINT_L_D + FTINT_L_S + FTINT_W_D + FTINT_W_S + IBAR + IDLE + INVTLB + IOCSRRD_B + IOCSRRD_D + IOCSRRD_H + IOCSRRD_W + IOCSRWR_B + IOCSRWR_D + IOCSRWR_H + IOCSRWR_W + JIRL + LDDIR + LDGT_B + LDGT_D + LDGT_H + LDGT_W + LDLE_B + LDLE_D + LDLE_H + LDLE_W + LDPTE + LDPTR_D + LDPTR_W + LDX_B + LDX_BU + LDX_D + LDX_H + LDX_HU + LDX_W + LDX_WU + LD_B + LD_BU + LD_D + LD_H + LD_HU + LD_W + LD_WU + LLACQ_D + LLACQ_W + LL_D + LL_W + LU12I_W + LU32I_D + LU52I_D + MASKEQZ + MASKNEZ + MOD_D + MOD_DU + MOD_W + MOD_WU + MOVCF2FR + MOVCF2GR + MOVFCSR2GR + MOVFR2CF + MOVFR2GR_D + MOVFR2GR_S + MOVFRH2GR_S + MOVGR2CF + MOVGR2FCSR + MOVGR2FRH_W + MOVGR2FR_D + MOVGR2FR_W + MULH_D + MULH_DU + MULH_W + MULH_WU + MULW_D_W + MULW_D_WU + MUL_D + MUL_W + NOR + OR + ORI + ORN + PCADDI + PCADDU12I + PCADDU18I + PCALAU12I + PRELD + PRELDX + RDTIMEH_W + RDTIMEL_W + RDTIME_D + REVB_2H + REVB_2W + REVB_4H + REVB_D + REVH_2W + REVH_D + ROTRI_D + ROTRI_W + ROTR_D + ROTR_W + SCREL_D + SCREL_W + SC_D + SC_Q + SC_W + SLLI_D + SLLI_W + SLL_D + SLL_W + SLT + SLTI + SLTU + SLTUI + SRAI_D + SRAI_W + SRA_D + SRA_W + SRLI_D + SRLI_W + SRL_D + SRL_W + STGT_B + STGT_D + STGT_H + STGT_W + STLE_B + STLE_D + STLE_H + STLE_W + STPTR_D + STPTR_W + STX_B + STX_D + STX_H + STX_W + ST_B + ST_D + ST_H + ST_W + SUB_D + SUB_W + SYSCALL + TLBCLR + TLBFILL + TLBFLUSH + TLBRD + TLBSRCH + TLBWR + XOR + XORI +) + +var opstr = [...]string{ + ADDI_D: "ADDI.D", + ADDI_W: "ADDI.W", + ADDU16I_D: "ADDU16I.D", + ADD_D: "ADD.D", + ADD_W: "ADD.W", + ALSL_D: "ALSL.D", + ALSL_W: "ALSL.W", + ALSL_WU: "ALSL.WU", + AMADD_B: "AMADD.B", + AMADD_D: "AMADD.D", + AMADD_DB_B: "AMADD_DB.B", + AMADD_DB_D: "AMADD_DB.D", + AMADD_DB_H: "AMADD_DB.H", + AMADD_DB_W: "AMADD_DB.W", + AMADD_H: "AMADD.H", + AMADD_W: "AMADD.W", + AMAND_D: "AMAND.D", + AMAND_DB_D: "AMAND_DB.D", + AMAND_DB_W: "AMAND_DB.W", + AMAND_W: "AMAND.W", + AMCAS_B: "AMCAS.B", + AMCAS_D: "AMCAS.D", + AMCAS_DB_B: "AMCAS_DB.B", + AMCAS_DB_D: "AMCAS_DB.D", + AMCAS_DB_H: "AMCAS_DB.H", + AMCAS_DB_W: "AMCAS_DB.W", + AMCAS_H: "AMCAS.H", + AMCAS_W: "AMCAS.W", + AMMAX_D: "AMMAX.D", + AMMAX_DB_D: "AMMAX_DB.D", + AMMAX_DB_DU: "AMMAX_DB.DU", + AMMAX_DB_W: "AMMAX_DB.W", + AMMAX_DB_WU: "AMMAX_DB.WU", + AMMAX_DU: "AMMAX.DU", + AMMAX_W: "AMMAX.W", + AMMAX_WU: "AMMAX.WU", + AMMIN_D: "AMMIN.D", + AMMIN_DB_D: "AMMIN_DB.D", + AMMIN_DB_DU: "AMMIN_DB.DU", + AMMIN_DB_W: "AMMIN_DB.W", + AMMIN_DB_WU: "AMMIN_DB.WU", + AMMIN_DU: "AMMIN.DU", + AMMIN_W: "AMMIN.W", + AMMIN_WU: "AMMIN.WU", + AMOR_D: "AMOR.D", + AMOR_DB_D: "AMOR_DB.D", + AMOR_DB_W: "AMOR_DB.W", + AMOR_W: "AMOR.W", + AMSWAP_B: "AMSWAP.B", + AMSWAP_D: "AMSWAP.D", + AMSWAP_DB_B: "AMSWAP_DB.B", + AMSWAP_DB_D: "AMSWAP_DB.D", + AMSWAP_DB_H: "AMSWAP_DB.H", + AMSWAP_DB_W: "AMSWAP_DB.W", + AMSWAP_H: "AMSWAP.H", + AMSWAP_W: "AMSWAP.W", + AMXOR_D: "AMXOR.D", + AMXOR_DB_D: "AMXOR_DB.D", + AMXOR_DB_W: "AMXOR_DB.W", + AMXOR_W: "AMXOR.W", + AND: "AND", + ANDI: "ANDI", + ANDN: "ANDN", + ASRTGT_D: "ASRTGT.D", + ASRTLE_D: "ASRTLE.D", + B: "B", + BCEQZ: "BCEQZ", + BCNEZ: "BCNEZ", + BEQ: "BEQ", + BEQZ: "BEQZ", + BGE: "BGE", + BGEU: "BGEU", + BITREV_4B: "BITREV.4B", + BITREV_8B: "BITREV.8B", + BITREV_D: "BITREV.D", + BITREV_W: "BITREV.W", + BL: "BL", + BLT: "BLT", + BLTU: "BLTU", + BNE: "BNE", + BNEZ: "BNEZ", + BREAK: "BREAK", + BSTRINS_D: "BSTRINS.D", + BSTRINS_W: "BSTRINS.W", + BSTRPICK_D: "BSTRPICK.D", + BSTRPICK_W: "BSTRPICK.W", + BYTEPICK_D: "BYTEPICK.D", + BYTEPICK_W: "BYTEPICK.W", + CACOP: "CACOP", + CLO_D: "CLO.D", + CLO_W: "CLO.W", + CLZ_D: "CLZ.D", + CLZ_W: "CLZ.W", + CPUCFG: "CPUCFG", + CRCC_W_B_W: "CRCC.W.B.W", + CRCC_W_D_W: "CRCC.W.D.W", + CRCC_W_H_W: "CRCC.W.H.W", + CRCC_W_W_W: "CRCC.W.W.W", + CRC_W_B_W: "CRC.W.B.W", + CRC_W_D_W: "CRC.W.D.W", + CRC_W_H_W: "CRC.W.H.W", + CRC_W_W_W: "CRC.W.W.W", + CSRRD: "CSRRD", + CSRWR: "CSRWR", + CSRXCHG: "CSRXCHG", + CTO_D: "CTO.D", + CTO_W: "CTO.W", + CTZ_D: "CTZ.D", + CTZ_W: "CTZ.W", + DBAR: "DBAR", + DBCL: "DBCL", + DIV_D: "DIV.D", + DIV_DU: "DIV.DU", + DIV_W: "DIV.W", + DIV_WU: "DIV.WU", + ERTN: "ERTN", + EXT_W_B: "EXT.W.B", + EXT_W_H: "EXT.W.H", + FABS_D: "FABS.D", + FABS_S: "FABS.S", + FADD_D: "FADD.D", + FADD_S: "FADD.S", + FCLASS_D: "FCLASS.D", + FCLASS_S: "FCLASS.S", + FCMP_CAF_D: "FCMP.CAF.D", + FCMP_CAF_S: "FCMP.CAF.S", + FCMP_CEQ_D: "FCMP.CEQ.D", + FCMP_CEQ_S: "FCMP.CEQ.S", + FCMP_CLE_D: "FCMP.CLE.D", + FCMP_CLE_S: "FCMP.CLE.S", + FCMP_CLT_D: "FCMP.CLT.D", + FCMP_CLT_S: "FCMP.CLT.S", + FCMP_CNE_D: "FCMP.CNE.D", + FCMP_CNE_S: "FCMP.CNE.S", + FCMP_COR_D: "FCMP.COR.D", + FCMP_COR_S: "FCMP.COR.S", + FCMP_CUEQ_D: "FCMP.CUEQ.D", + FCMP_CUEQ_S: "FCMP.CUEQ.S", + FCMP_CULE_D: "FCMP.CULE.D", + FCMP_CULE_S: "FCMP.CULE.S", + FCMP_CULT_D: "FCMP.CULT.D", + FCMP_CULT_S: "FCMP.CULT.S", + FCMP_CUNE_D: "FCMP.CUNE.D", + FCMP_CUNE_S: "FCMP.CUNE.S", + FCMP_CUN_D: "FCMP.CUN.D", + FCMP_CUN_S: "FCMP.CUN.S", + FCMP_SAF_D: "FCMP.SAF.D", + FCMP_SAF_S: "FCMP.SAF.S", + FCMP_SEQ_D: "FCMP.SEQ.D", + FCMP_SEQ_S: "FCMP.SEQ.S", + FCMP_SLE_D: "FCMP.SLE.D", + FCMP_SLE_S: "FCMP.SLE.S", + FCMP_SLT_D: "FCMP.SLT.D", + FCMP_SLT_S: "FCMP.SLT.S", + FCMP_SNE_D: "FCMP.SNE.D", + FCMP_SNE_S: "FCMP.SNE.S", + FCMP_SOR_D: "FCMP.SOR.D", + FCMP_SOR_S: "FCMP.SOR.S", + FCMP_SUEQ_D: "FCMP.SUEQ.D", + FCMP_SUEQ_S: "FCMP.SUEQ.S", + FCMP_SULE_D: "FCMP.SULE.D", + FCMP_SULE_S: "FCMP.SULE.S", + FCMP_SULT_D: "FCMP.SULT.D", + FCMP_SULT_S: "FCMP.SULT.S", + FCMP_SUNE_D: "FCMP.SUNE.D", + FCMP_SUNE_S: "FCMP.SUNE.S", + FCMP_SUN_D: "FCMP.SUN.D", + FCMP_SUN_S: "FCMP.SUN.S", + FCOPYSIGN_D: "FCOPYSIGN.D", + FCOPYSIGN_S: "FCOPYSIGN.S", + FCVT_D_S: "FCVT.D.S", + FCVT_S_D: "FCVT.S.D", + FDIV_D: "FDIV.D", + FDIV_S: "FDIV.S", + FFINT_D_L: "FFINT.D.L", + FFINT_D_W: "FFINT.D.W", + FFINT_S_L: "FFINT.S.L", + FFINT_S_W: "FFINT.S.W", + FLDGT_D: "FLDGT.D", + FLDGT_S: "FLDGT.S", + FLDLE_D: "FLDLE.D", + FLDLE_S: "FLDLE.S", + FLDX_D: "FLDX.D", + FLDX_S: "FLDX.S", + FLD_D: "FLD.D", + FLD_S: "FLD.S", + FLOGB_D: "FLOGB.D", + FLOGB_S: "FLOGB.S", + FMADD_D: "FMADD.D", + FMADD_S: "FMADD.S", + FMAXA_D: "FMAXA.D", + FMAXA_S: "FMAXA.S", + FMAX_D: "FMAX.D", + FMAX_S: "FMAX.S", + FMINA_D: "FMINA.D", + FMINA_S: "FMINA.S", + FMIN_D: "FMIN.D", + FMIN_S: "FMIN.S", + FMOV_D: "FMOV.D", + FMOV_S: "FMOV.S", + FMSUB_D: "FMSUB.D", + FMSUB_S: "FMSUB.S", + FMUL_D: "FMUL.D", + FMUL_S: "FMUL.S", + FNEG_D: "FNEG.D", + FNEG_S: "FNEG.S", + FNMADD_D: "FNMADD.D", + FNMADD_S: "FNMADD.S", + FNMSUB_D: "FNMSUB.D", + FNMSUB_S: "FNMSUB.S", + FRECIPE_D: "FRECIPE.D", + FRECIPE_S: "FRECIPE.S", + FRECIP_D: "FRECIP.D", + FRECIP_S: "FRECIP.S", + FRINT_D: "FRINT.D", + FRINT_S: "FRINT.S", + FRSQRTE_D: "FRSQRTE.D", + FRSQRTE_S: "FRSQRTE.S", + FRSQRT_D: "FRSQRT.D", + FRSQRT_S: "FRSQRT.S", + FSCALEB_D: "FSCALEB.D", + FSCALEB_S: "FSCALEB.S", + FSEL: "FSEL", + FSQRT_D: "FSQRT.D", + FSQRT_S: "FSQRT.S", + FSTGT_D: "FSTGT.D", + FSTGT_S: "FSTGT.S", + FSTLE_D: "FSTLE.D", + FSTLE_S: "FSTLE.S", + FSTX_D: "FSTX.D", + FSTX_S: "FSTX.S", + FST_D: "FST.D", + FST_S: "FST.S", + FSUB_D: "FSUB.D", + FSUB_S: "FSUB.S", + FTINTRM_L_D: "FTINTRM.L.D", + FTINTRM_L_S: "FTINTRM.L.S", + FTINTRM_W_D: "FTINTRM.W.D", + FTINTRM_W_S: "FTINTRM.W.S", + FTINTRNE_L_D: "FTINTRNE.L.D", + FTINTRNE_L_S: "FTINTRNE.L.S", + FTINTRNE_W_D: "FTINTRNE.W.D", + FTINTRNE_W_S: "FTINTRNE.W.S", + FTINTRP_L_D: "FTINTRP.L.D", + FTINTRP_L_S: "FTINTRP.L.S", + FTINTRP_W_D: "FTINTRP.W.D", + FTINTRP_W_S: "FTINTRP.W.S", + FTINTRZ_L_D: "FTINTRZ.L.D", + FTINTRZ_L_S: "FTINTRZ.L.S", + FTINTRZ_W_D: "FTINTRZ.W.D", + FTINTRZ_W_S: "FTINTRZ.W.S", + FTINT_L_D: "FTINT.L.D", + FTINT_L_S: "FTINT.L.S", + FTINT_W_D: "FTINT.W.D", + FTINT_W_S: "FTINT.W.S", + IBAR: "IBAR", + IDLE: "IDLE", + INVTLB: "INVTLB", + IOCSRRD_B: "IOCSRRD.B", + IOCSRRD_D: "IOCSRRD.D", + IOCSRRD_H: "IOCSRRD.H", + IOCSRRD_W: "IOCSRRD.W", + IOCSRWR_B: "IOCSRWR.B", + IOCSRWR_D: "IOCSRWR.D", + IOCSRWR_H: "IOCSRWR.H", + IOCSRWR_W: "IOCSRWR.W", + JIRL: "JIRL", + LDDIR: "LDDIR", + LDGT_B: "LDGT.B", + LDGT_D: "LDGT.D", + LDGT_H: "LDGT.H", + LDGT_W: "LDGT.W", + LDLE_B: "LDLE.B", + LDLE_D: "LDLE.D", + LDLE_H: "LDLE.H", + LDLE_W: "LDLE.W", + LDPTE: "LDPTE", + LDPTR_D: "LDPTR.D", + LDPTR_W: "LDPTR.W", + LDX_B: "LDX.B", + LDX_BU: "LDX.BU", + LDX_D: "LDX.D", + LDX_H: "LDX.H", + LDX_HU: "LDX.HU", + LDX_W: "LDX.W", + LDX_WU: "LDX.WU", + LD_B: "LD.B", + LD_BU: "LD.BU", + LD_D: "LD.D", + LD_H: "LD.H", + LD_HU: "LD.HU", + LD_W: "LD.W", + LD_WU: "LD.WU", + LLACQ_D: "LLACQ.D", + LLACQ_W: "LLACQ.W", + LL_D: "LL.D", + LL_W: "LL.W", + LU12I_W: "LU12I.W", + LU32I_D: "LU32I.D", + LU52I_D: "LU52I.D", + MASKEQZ: "MASKEQZ", + MASKNEZ: "MASKNEZ", + MOD_D: "MOD.D", + MOD_DU: "MOD.DU", + MOD_W: "MOD.W", + MOD_WU: "MOD.WU", + MOVCF2FR: "MOVCF2FR", + MOVCF2GR: "MOVCF2GR", + MOVFCSR2GR: "MOVFCSR2GR", + MOVFR2CF: "MOVFR2CF", + MOVFR2GR_D: "MOVFR2GR.D", + MOVFR2GR_S: "MOVFR2GR.S", + MOVFRH2GR_S: "MOVFRH2GR.S", + MOVGR2CF: "MOVGR2CF", + MOVGR2FCSR: "MOVGR2FCSR", + MOVGR2FRH_W: "MOVGR2FRH.W", + MOVGR2FR_D: "MOVGR2FR.D", + MOVGR2FR_W: "MOVGR2FR.W", + MULH_D: "MULH.D", + MULH_DU: "MULH.DU", + MULH_W: "MULH.W", + MULH_WU: "MULH.WU", + MULW_D_W: "MULW.D.W", + MULW_D_WU: "MULW.D.WU", + MUL_D: "MUL.D", + MUL_W: "MUL.W", + NOR: "NOR", + OR: "OR", + ORI: "ORI", + ORN: "ORN", + PCADDI: "PCADDI", + PCADDU12I: "PCADDU12I", + PCADDU18I: "PCADDU18I", + PCALAU12I: "PCALAU12I", + PRELD: "PRELD", + PRELDX: "PRELDX", + RDTIMEH_W: "RDTIMEH.W", + RDTIMEL_W: "RDTIMEL.W", + RDTIME_D: "RDTIME.D", + REVB_2H: "REVB.2H", + REVB_2W: "REVB.2W", + REVB_4H: "REVB.4H", + REVB_D: "REVB.D", + REVH_2W: "REVH.2W", + REVH_D: "REVH.D", + ROTRI_D: "ROTRI.D", + ROTRI_W: "ROTRI.W", + ROTR_D: "ROTR.D", + ROTR_W: "ROTR.W", + SCREL_D: "SCREL.D", + SCREL_W: "SCREL.W", + SC_D: "SC.D", + SC_Q: "SC.Q", + SC_W: "SC.W", + SLLI_D: "SLLI.D", + SLLI_W: "SLLI.W", + SLL_D: "SLL.D", + SLL_W: "SLL.W", + SLT: "SLT", + SLTI: "SLTI", + SLTU: "SLTU", + SLTUI: "SLTUI", + SRAI_D: "SRAI.D", + SRAI_W: "SRAI.W", + SRA_D: "SRA.D", + SRA_W: "SRA.W", + SRLI_D: "SRLI.D", + SRLI_W: "SRLI.W", + SRL_D: "SRL.D", + SRL_W: "SRL.W", + STGT_B: "STGT.B", + STGT_D: "STGT.D", + STGT_H: "STGT.H", + STGT_W: "STGT.W", + STLE_B: "STLE.B", + STLE_D: "STLE.D", + STLE_H: "STLE.H", + STLE_W: "STLE.W", + STPTR_D: "STPTR.D", + STPTR_W: "STPTR.W", + STX_B: "STX.B", + STX_D: "STX.D", + STX_H: "STX.H", + STX_W: "STX.W", + ST_B: "ST.B", + ST_D: "ST.D", + ST_H: "ST.H", + ST_W: "ST.W", + SUB_D: "SUB.D", + SUB_W: "SUB.W", + SYSCALL: "SYSCALL", + TLBCLR: "TLBCLR", + TLBFILL: "TLBFILL", + TLBFLUSH: "TLBFLUSH", + TLBRD: "TLBRD", + TLBSRCH: "TLBSRCH", + TLBWR: "TLBWR", + XOR: "XOR", + XORI: "XORI", +} + +var instFormats = [...]instFormat{ + // ADDI.D rd, rj, si12 + {mask: 0xffc00000, value: 0x02c00000, op: ADDI_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // ADDI.W rd, rj, si12 + {mask: 0xffc00000, value: 0x02800000, op: ADDI_W, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // ADDU16I.D rd, rj, si16 + {mask: 0xfc000000, value: 0x10000000, op: ADDU16I_D, args: instArgs{arg_rd, arg_rj, arg_si16_25_10}}, + // ADD.D rd, rj, rk + {mask: 0xffff8000, value: 0x00108000, op: ADD_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // ADD.W rd, rj, rk + {mask: 0xffff8000, value: 0x00100000, op: ADD_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // ALSL.D rd, rj, rk, sa2 + {mask: 0xfffe0000, value: 0x002c0000, op: ALSL_D, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}}, + // ALSL.W rd, rj, rk, sa2 + {mask: 0xfffe0000, value: 0x00040000, op: ALSL_W, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}}, + // ALSL.WU rd, rj, rk, sa2 + {mask: 0xfffe0000, value: 0x00060000, op: ALSL_WU, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}}, + // AMADD.B rd, rk, rj + {mask: 0xffff8000, value: 0x385d0000, op: AMADD_B, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMADD.D rd, rk, rj + {mask: 0xffff8000, value: 0x38618000, op: AMADD_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMADD_DB.B rd, rk, rj + {mask: 0xffff8000, value: 0x385f0000, op: AMADD_DB_B, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMADD_DB.D rd, rk, rj + {mask: 0xffff8000, value: 0x386a8000, op: AMADD_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMADD_DB.H rd, rk, rj + {mask: 0xffff8000, value: 0x385f8000, op: AMADD_DB_H, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMADD_DB.W rd, rk, rj + {mask: 0xffff8000, value: 0x386a0000, op: AMADD_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMADD.H rd, rk, rj + {mask: 0xffff8000, value: 0x385d8000, op: AMADD_H, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMADD.W rd, rk, rj + {mask: 0xffff8000, value: 0x38610000, op: AMADD_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMAND.D rd, rk, rj + {mask: 0xffff8000, value: 0x38628000, op: AMAND_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMAND_DB.D rd, rk, rj + {mask: 0xffff8000, value: 0x386b8000, op: AMAND_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMAND_DB.W rd, rk, rj + {mask: 0xffff8000, value: 0x386b0000, op: AMAND_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMAND.W rd, rk, rj + {mask: 0xffff8000, value: 0x38620000, op: AMAND_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMCAS.B rd, rk, rj + {mask: 0xffff8000, value: 0x38580000, op: AMCAS_B, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMCAS.D rd, rk, rj + {mask: 0xffff8000, value: 0x38598000, op: AMCAS_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMCAS_DB.B rd, rk, rj + {mask: 0xffff8000, value: 0x385a0000, op: AMCAS_DB_B, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMCAS_DB.D rd, rk, rj + {mask: 0xffff8000, value: 0x385b8000, op: AMCAS_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMCAS_DB.H rd, rk, rj + {mask: 0xffff8000, value: 0x385a8000, op: AMCAS_DB_H, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMCAS_DB.W rd, rk, rj + {mask: 0xffff8000, value: 0x385b0000, op: AMCAS_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMCAS.H rd, rk, rj + {mask: 0xffff8000, value: 0x38588000, op: AMCAS_H, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMCAS.W rd, rk, rj + {mask: 0xffff8000, value: 0x38590000, op: AMCAS_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMAX.D rd, rk, rj + {mask: 0xffff8000, value: 0x38658000, op: AMMAX_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMAX_DB.D rd, rk, rj + {mask: 0xffff8000, value: 0x386e8000, op: AMMAX_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMAX_DB.DU rd, rk, rj + {mask: 0xffff8000, value: 0x38708000, op: AMMAX_DB_DU, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMAX_DB.W rd, rk, rj + {mask: 0xffff8000, value: 0x386e0000, op: AMMAX_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMAX_DB.WU rd, rk, rj + {mask: 0xffff8000, value: 0x38700000, op: AMMAX_DB_WU, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMAX.DU rd, rk, rj + {mask: 0xffff8000, value: 0x38678000, op: AMMAX_DU, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMAX.W rd, rk, rj + {mask: 0xffff8000, value: 0x38650000, op: AMMAX_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMAX.WU rd, rk, rj + {mask: 0xffff8000, value: 0x38670000, op: AMMAX_WU, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMIN.D rd, rk, rj + {mask: 0xffff8000, value: 0x38668000, op: AMMIN_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMIN_DB.D rd, rk, rj + {mask: 0xffff8000, value: 0x386f8000, op: AMMIN_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMIN_DB.DU rd, rk, rj + {mask: 0xffff8000, value: 0x38718000, op: AMMIN_DB_DU, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMIN_DB.W rd, rk, rj + {mask: 0xffff8000, value: 0x386f0000, op: AMMIN_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMIN_DB.WU rd, rk, rj + {mask: 0xffff8000, value: 0x38710000, op: AMMIN_DB_WU, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMIN.DU rd, rk, rj + {mask: 0xffff8000, value: 0x38688000, op: AMMIN_DU, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMIN.W rd, rk, rj + {mask: 0xffff8000, value: 0x38660000, op: AMMIN_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMMIN.WU rd, rk, rj + {mask: 0xffff8000, value: 0x38680000, op: AMMIN_WU, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMOR.D rd, rk, rj + {mask: 0xffff8000, value: 0x38638000, op: AMOR_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMOR_DB.D rd, rk, rj + {mask: 0xffff8000, value: 0x386c8000, op: AMOR_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMOR_DB.W rd, rk, rj + {mask: 0xffff8000, value: 0x386c0000, op: AMOR_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMOR.W rd, rk, rj + {mask: 0xffff8000, value: 0x38630000, op: AMOR_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMSWAP.B rd, rk, rj + {mask: 0xffff8000, value: 0x385c0000, op: AMSWAP_B, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMSWAP.D rd, rk, rj + {mask: 0xffff8000, value: 0x38608000, op: AMSWAP_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMSWAP_DB.B rd, rk, rj + {mask: 0xffff8000, value: 0x385e0000, op: AMSWAP_DB_B, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMSWAP_DB.D rd, rk, rj + {mask: 0xffff8000, value: 0x38698000, op: AMSWAP_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMSWAP_DB.H rd, rk, rj + {mask: 0xffff8000, value: 0x385e8000, op: AMSWAP_DB_H, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMSWAP_DB.W rd, rk, rj + {mask: 0xffff8000, value: 0x38690000, op: AMSWAP_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMSWAP.H rd, rk, rj + {mask: 0xffff8000, value: 0x385c8000, op: AMSWAP_H, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMSWAP.W rd, rk, rj + {mask: 0xffff8000, value: 0x38600000, op: AMSWAP_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMXOR.D rd, rk, rj + {mask: 0xffff8000, value: 0x38648000, op: AMXOR_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMXOR_DB.D rd, rk, rj + {mask: 0xffff8000, value: 0x386d8000, op: AMXOR_DB_D, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMXOR_DB.W rd, rk, rj + {mask: 0xffff8000, value: 0x386d0000, op: AMXOR_DB_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AMXOR.W rd, rk, rj + {mask: 0xffff8000, value: 0x38640000, op: AMXOR_W, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // AND rd, rj, rk + {mask: 0xffff8000, value: 0x00148000, op: AND, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // ANDI rd, rj, ui12 + {mask: 0xffc00000, value: 0x03400000, op: ANDI, args: instArgs{arg_rd, arg_rj, arg_ui12_21_10}}, + // ANDN rd, rj, rk + {mask: 0xffff8000, value: 0x00168000, op: ANDN, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // ASRTGT.D rj, rk + {mask: 0xffff801f, value: 0x00018000, op: ASRTGT_D, args: instArgs{arg_rj, arg_rk}}, + // ASRTLE.D rj, rk + {mask: 0xffff801f, value: 0x00010000, op: ASRTLE_D, args: instArgs{arg_rj, arg_rk}}, + // B offs + {mask: 0xfc000000, value: 0x50000000, op: B, args: instArgs{arg_offset_25_0}}, + // BCEQZ cj, offs + {mask: 0xfc000300, value: 0x48000000, op: BCEQZ, args: instArgs{arg_cj, arg_offset_20_0}}, + // BCNEZ cj, offs + {mask: 0xfc000300, value: 0x48000100, op: BCNEZ, args: instArgs{arg_cj, arg_offset_20_0}}, + // BEQ rj, rd, offs + {mask: 0xfc000000, value: 0x58000000, op: BEQ, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, + // BEQZ rj, offs + {mask: 0xfc000000, value: 0x40000000, op: BEQZ, args: instArgs{arg_rj, arg_offset_20_0}}, + // BGE rj, rd, offs + {mask: 0xfc000000, value: 0x64000000, op: BGE, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, + // BGEU rj, rd, offs + {mask: 0xfc000000, value: 0x6c000000, op: BGEU, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, + // BITREV.4B rd, rj + {mask: 0xfffffc00, value: 0x00004800, op: BITREV_4B, args: instArgs{arg_rd, arg_rj}}, + // BITREV.8B rd, rj + {mask: 0xfffffc00, value: 0x00004c00, op: BITREV_8B, args: instArgs{arg_rd, arg_rj}}, + // BITREV.D rd, rj + {mask: 0xfffffc00, value: 0x00005400, op: BITREV_D, args: instArgs{arg_rd, arg_rj}}, + // BITREV.W rd, rj + {mask: 0xfffffc00, value: 0x00005000, op: BITREV_W, args: instArgs{arg_rd, arg_rj}}, + // BL offs + {mask: 0xfc000000, value: 0x54000000, op: BL, args: instArgs{arg_offset_25_0}}, + // BLT rj, rd, offs + {mask: 0xfc000000, value: 0x60000000, op: BLT, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, + // BLTU rj, rd, offs + {mask: 0xfc000000, value: 0x68000000, op: BLTU, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, + // BNE rj, rd, offs + {mask: 0xfc000000, value: 0x5c000000, op: BNE, args: instArgs{arg_rj, arg_rd, arg_offset_15_0}}, + // BNEZ rj, offs + {mask: 0xfc000000, value: 0x44000000, op: BNEZ, args: instArgs{arg_rj, arg_offset_20_0}}, + // BREAK code + {mask: 0xffff8000, value: 0x002a0000, op: BREAK, args: instArgs{arg_code_14_0}}, + // BSTRINS.D rd, rj, msbd, lsbd + {mask: 0xffc00000, value: 0x00800000, op: BSTRINS_D, args: instArgs{arg_rd, arg_rj, arg_msbd, arg_lsbd}}, + // BSTRINS.W rd, rj, msbw, lsbw + {mask: 0xffe08000, value: 0x00600000, op: BSTRINS_W, args: instArgs{arg_rd, arg_rj, arg_msbw, arg_lsbw}}, + // BSTRPICK.D rd, rj, msbd, lsbd + {mask: 0xffc00000, value: 0x00c00000, op: BSTRPICK_D, args: instArgs{arg_rd, arg_rj, arg_msbd, arg_lsbd}}, + // BSTRPICK.W rd, rj, msbw, lsbw + {mask: 0xffe08000, value: 0x00608000, op: BSTRPICK_W, args: instArgs{arg_rd, arg_rj, arg_msbw, arg_lsbw}}, + // BYTEPICK.D rd, rj, rk, sa3 + {mask: 0xfffc0000, value: 0x000c0000, op: BYTEPICK_D, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa3_17_15}}, + // BYTEPICK.W rd, rj, rk, sa2 + {mask: 0xfffe0000, value: 0x00080000, op: BYTEPICK_W, args: instArgs{arg_rd, arg_rj, arg_rk, arg_sa2_16_15}}, + // CACOP code, rj, si12 + {mask: 0xffc00000, value: 0x06000000, op: CACOP, args: instArgs{arg_code_4_0, arg_rj, arg_si12_21_10}}, + // CLO.D rd, rj + {mask: 0xfffffc00, value: 0x00002000, op: CLO_D, args: instArgs{arg_rd, arg_rj}}, + // CLO.W rd, rj + {mask: 0xfffffc00, value: 0x00001000, op: CLO_W, args: instArgs{arg_rd, arg_rj}}, + // CLZ.D rd, rj + {mask: 0xfffffc00, value: 0x00002400, op: CLZ_D, args: instArgs{arg_rd, arg_rj}}, + // CLZ.W rd, rj + {mask: 0xfffffc00, value: 0x00001400, op: CLZ_W, args: instArgs{arg_rd, arg_rj}}, + // CPUCFG rd, rj + {mask: 0xfffffc00, value: 0x00006c00, op: CPUCFG, args: instArgs{arg_rd, arg_rj}}, + // CRCC.W.B.W rd, rj, rk + {mask: 0xffff8000, value: 0x00260000, op: CRCC_W_B_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // CRCC.W.D.W rd, rj, rk + {mask: 0xffff8000, value: 0x00278000, op: CRCC_W_D_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // CRCC.W.H.W rd, rj, rk + {mask: 0xffff8000, value: 0x00268000, op: CRCC_W_H_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // CRCC.W.W.W rd, rj, rk + {mask: 0xffff8000, value: 0x00270000, op: CRCC_W_W_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // CRC.W.B.W rd, rj, rk + {mask: 0xffff8000, value: 0x00240000, op: CRC_W_B_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // CRC.W.D.W rd, rj, rk + {mask: 0xffff8000, value: 0x00258000, op: CRC_W_D_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // CRC.W.H.W rd, rj, rk + {mask: 0xffff8000, value: 0x00248000, op: CRC_W_H_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // CRC.W.W.W rd, rj, rk + {mask: 0xffff8000, value: 0x00250000, op: CRC_W_W_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // CSRRD rd, csr + {mask: 0xff0003e0, value: 0x04000000, op: CSRRD, args: instArgs{arg_rd, arg_csr_23_10}}, + // CSRWR rd, csr + {mask: 0xff0003e0, value: 0x04000020, op: CSRWR, args: instArgs{arg_rd, arg_csr_23_10}}, + // CSRXCHG rd, rj, csr + {mask: 0xff000000, value: 0x04000000, op: CSRXCHG, args: instArgs{arg_rd, arg_rj, arg_csr_23_10}}, + // CTO.D rd, rj + {mask: 0xfffffc00, value: 0x00002800, op: CTO_D, args: instArgs{arg_rd, arg_rj}}, + // CTO.W rd, rj + {mask: 0xfffffc00, value: 0x00001800, op: CTO_W, args: instArgs{arg_rd, arg_rj}}, + // CTZ.D rd, rj + {mask: 0xfffffc00, value: 0x00002c00, op: CTZ_D, args: instArgs{arg_rd, arg_rj}}, + // CTZ.W rd, rj + {mask: 0xfffffc00, value: 0x00001c00, op: CTZ_W, args: instArgs{arg_rd, arg_rj}}, + // DBAR hint + {mask: 0xffff8000, value: 0x38720000, op: DBAR, args: instArgs{arg_hint_14_0}}, + // DBCL code + {mask: 0xffff8000, value: 0x002a8000, op: DBCL, args: instArgs{arg_code_14_0}}, + // DIV.D rd, rj, rk + {mask: 0xffff8000, value: 0x00220000, op: DIV_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // DIV.DU rd, rj, rk + {mask: 0xffff8000, value: 0x00230000, op: DIV_DU, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // DIV.W rd, rj, rk + {mask: 0xffff8000, value: 0x00200000, op: DIV_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // DIV.WU rd, rj, rk + {mask: 0xffff8000, value: 0x00210000, op: DIV_WU, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // ERTN + {mask: 0xffffffff, value: 0x06483800, op: ERTN, args: instArgs{}}, + // EXT.W.B rd, rj + {mask: 0xfffffc00, value: 0x00005c00, op: EXT_W_B, args: instArgs{arg_rd, arg_rj}}, + // EXT.W.H rd, rj + {mask: 0xfffffc00, value: 0x00005800, op: EXT_W_H, args: instArgs{arg_rd, arg_rj}}, + // FABS.D fd, fj + {mask: 0xfffffc00, value: 0x01140800, op: FABS_D, args: instArgs{arg_fd, arg_fj}}, + // FABS.S fd, fj + {mask: 0xfffffc00, value: 0x01140400, op: FABS_S, args: instArgs{arg_fd, arg_fj}}, + // FADD.D fd, fj, fk + {mask: 0xffff8000, value: 0x01010000, op: FADD_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FADD.S fd, fj, fk + {mask: 0xffff8000, value: 0x01008000, op: FADD_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FCLASS.D fd, fj + {mask: 0xfffffc00, value: 0x01143800, op: FCLASS_D, args: instArgs{arg_fd, arg_fj}}, + // FCLASS.S fd, fj + {mask: 0xfffffc00, value: 0x01143400, op: FCLASS_S, args: instArgs{arg_fd, arg_fj}}, + // FCMP.CAF.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c200000, op: FCMP_CAF_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CAF.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c100000, op: FCMP_CAF_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CEQ.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c220000, op: FCMP_CEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CEQ.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c120000, op: FCMP_CEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CLE.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c230000, op: FCMP_CLE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CLE.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c130000, op: FCMP_CLE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CLT.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c210000, op: FCMP_CLT_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CLT.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c110000, op: FCMP_CLT_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CNE.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c280000, op: FCMP_CNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CNE.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c180000, op: FCMP_CNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.COR.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c2a0000, op: FCMP_COR_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.COR.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c1a0000, op: FCMP_COR_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CUEQ.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c260000, op: FCMP_CUEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CUEQ.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c160000, op: FCMP_CUEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CULE.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c270000, op: FCMP_CULE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CULE.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c170000, op: FCMP_CULE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CULT.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c250000, op: FCMP_CULT_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CULT.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c150000, op: FCMP_CULT_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CUNE.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c2c0000, op: FCMP_CUNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CUNE.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c1c0000, op: FCMP_CUNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CUN.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c240000, op: FCMP_CUN_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.CUN.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c140000, op: FCMP_CUN_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SAF.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c208000, op: FCMP_SAF_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SAF.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c108000, op: FCMP_SAF_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SEQ.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c228000, op: FCMP_SEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SEQ.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c128000, op: FCMP_SEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SLE.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c238000, op: FCMP_SLE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SLE.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c138000, op: FCMP_SLE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SLT.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c218000, op: FCMP_SLT_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SLT.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c118000, op: FCMP_SLT_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SNE.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c288000, op: FCMP_SNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SNE.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c188000, op: FCMP_SNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SOR.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c2a8000, op: FCMP_SOR_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SOR.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c1a8000, op: FCMP_SOR_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SUEQ.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c268000, op: FCMP_SUEQ_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SUEQ.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c168000, op: FCMP_SUEQ_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SULE.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c278000, op: FCMP_SULE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SULE.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c178000, op: FCMP_SULE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SULT.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c258000, op: FCMP_SULT_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SULT.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c158000, op: FCMP_SULT_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SUNE.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c2c8000, op: FCMP_SUNE_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SUNE.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c1c8000, op: FCMP_SUNE_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SUN.D cd, fj, fk + {mask: 0xffff8018, value: 0x0c248000, op: FCMP_SUN_D, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCMP.SUN.S cd, fj, fk + {mask: 0xffff8018, value: 0x0c148000, op: FCMP_SUN_S, args: instArgs{arg_cd, arg_fj, arg_fk}}, + // FCOPYSIGN.D fd, fj, fk + {mask: 0xffff8000, value: 0x01130000, op: FCOPYSIGN_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FCOPYSIGN.S fd, fj, fk + {mask: 0xffff8000, value: 0x01128000, op: FCOPYSIGN_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FCVT.D.S fd, fj + {mask: 0xfffffc00, value: 0x01192400, op: FCVT_D_S, args: instArgs{arg_fd, arg_fj}}, + // FCVT.S.D fd, fj + {mask: 0xfffffc00, value: 0x01191800, op: FCVT_S_D, args: instArgs{arg_fd, arg_fj}}, + // FDIV.D fd, fj, fk + {mask: 0xffff8000, value: 0x01070000, op: FDIV_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FDIV.S fd, fj, fk + {mask: 0xffff8000, value: 0x01068000, op: FDIV_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FFINT.D.L fd, fj + {mask: 0xfffffc00, value: 0x011d2800, op: FFINT_D_L, args: instArgs{arg_fd, arg_fj}}, + // FFINT.D.W fd, fj + {mask: 0xfffffc00, value: 0x011d2000, op: FFINT_D_W, args: instArgs{arg_fd, arg_fj}}, + // FFINT.S.L fd, fj + {mask: 0xfffffc00, value: 0x011d1800, op: FFINT_S_L, args: instArgs{arg_fd, arg_fj}}, + // FFINT.S.W fd, fj + {mask: 0xfffffc00, value: 0x011d1000, op: FFINT_S_W, args: instArgs{arg_fd, arg_fj}}, + // FLDGT.D fd, rj, rk + {mask: 0xffff8000, value: 0x38748000, op: FLDGT_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FLDGT.S fd, rj, rk + {mask: 0xffff8000, value: 0x38740000, op: FLDGT_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FLDLE.D fd, rj, rk + {mask: 0xffff8000, value: 0x38758000, op: FLDLE_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FLDLE.S fd, rj, rk + {mask: 0xffff8000, value: 0x38750000, op: FLDLE_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FLDX.D fd, rj, rk + {mask: 0xffff8000, value: 0x38340000, op: FLDX_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FLDX.S fd, rj, rk + {mask: 0xffff8000, value: 0x38300000, op: FLDX_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FLD.D fd, rj, si12 + {mask: 0xffc00000, value: 0x2b800000, op: FLD_D, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}}, + // FLD.S fd, rj, si12 + {mask: 0xffc00000, value: 0x2b000000, op: FLD_S, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}}, + // FLOGB.D fd, fj + {mask: 0xfffffc00, value: 0x01142800, op: FLOGB_D, args: instArgs{arg_fd, arg_fj}}, + // FLOGB.S fd, fj + {mask: 0xfffffc00, value: 0x01142400, op: FLOGB_S, args: instArgs{arg_fd, arg_fj}}, + // FMADD.D fd, fj, fk, fa + {mask: 0xfff00000, value: 0x08200000, op: FMADD_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, + // FMADD.S fd, fj, fk, fa + {mask: 0xfff00000, value: 0x08100000, op: FMADD_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, + // FMAXA.D fd, fj, fk + {mask: 0xffff8000, value: 0x010d0000, op: FMAXA_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FMAXA.S fd, fj, fk + {mask: 0xffff8000, value: 0x010c8000, op: FMAXA_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FMAX.D fd, fj, fk + {mask: 0xffff8000, value: 0x01090000, op: FMAX_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FMAX.S fd, fj, fk + {mask: 0xffff8000, value: 0x01088000, op: FMAX_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FMINA.D fd, fj, fk + {mask: 0xffff8000, value: 0x010f0000, op: FMINA_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FMINA.S fd, fj, fk + {mask: 0xffff8000, value: 0x010e8000, op: FMINA_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FMIN.D fd, fj, fk + {mask: 0xffff8000, value: 0x010b0000, op: FMIN_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FMIN.S fd, fj, fk + {mask: 0xffff8000, value: 0x010a8000, op: FMIN_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FMOV.D fd, fj + {mask: 0xfffffc00, value: 0x01149800, op: FMOV_D, args: instArgs{arg_fd, arg_fj}}, + // FMOV.S fd, fj + {mask: 0xfffffc00, value: 0x01149400, op: FMOV_S, args: instArgs{arg_fd, arg_fj}}, + // FMSUB.D fd, fj, fk, fa + {mask: 0xfff00000, value: 0x08600000, op: FMSUB_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, + // FMSUB.S fd, fj, fk, fa + {mask: 0xfff00000, value: 0x08500000, op: FMSUB_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, + // FMUL.D fd, fj, fk + {mask: 0xffff8000, value: 0x01050000, op: FMUL_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FMUL.S fd, fj, fk + {mask: 0xffff8000, value: 0x01048000, op: FMUL_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FNEG.D fd, fj + {mask: 0xfffffc00, value: 0x01141800, op: FNEG_D, args: instArgs{arg_fd, arg_fj}}, + // FNEG.S fd, fj + {mask: 0xfffffc00, value: 0x01141400, op: FNEG_S, args: instArgs{arg_fd, arg_fj}}, + // FNMADD.D fd, fj, fk, fa + {mask: 0xfff00000, value: 0x08a00000, op: FNMADD_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, + // FNMADD.S fd, fj, fk, fa + {mask: 0xfff00000, value: 0x08900000, op: FNMADD_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, + // FNMSUB.D fd, fj, fk, fa + {mask: 0xfff00000, value: 0x08e00000, op: FNMSUB_D, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, + // FNMSUB.S fd, fj, fk, fa + {mask: 0xfff00000, value: 0x08d00000, op: FNMSUB_S, args: instArgs{arg_fd, arg_fj, arg_fk, arg_fa}}, + // FRECIPE.D fd, fj + {mask: 0xfffffc00, value: 0x01147800, op: FRECIPE_D, args: instArgs{arg_fd, arg_fj}}, + // FRECIPE.S fd, fj + {mask: 0xfffffc00, value: 0x01147400, op: FRECIPE_S, args: instArgs{arg_fd, arg_fj}}, + // FRECIP.D fd, fj + {mask: 0xfffffc00, value: 0x01145800, op: FRECIP_D, args: instArgs{arg_fd, arg_fj}}, + // FRECIP.S fd, fj + {mask: 0xfffffc00, value: 0x01145400, op: FRECIP_S, args: instArgs{arg_fd, arg_fj}}, + // FRINT.D fd, fj + {mask: 0xfffffc00, value: 0x011e4800, op: FRINT_D, args: instArgs{arg_fd, arg_fj}}, + // FRINT.S fd, fj + {mask: 0xfffffc00, value: 0x011e4400, op: FRINT_S, args: instArgs{arg_fd, arg_fj}}, + // FRSQRTE.D fd, fj + {mask: 0xfffffc00, value: 0x01148800, op: FRSQRTE_D, args: instArgs{arg_fd, arg_fj}}, + // FRSQRTE.S fd, fj + {mask: 0xfffffc00, value: 0x01148400, op: FRSQRTE_S, args: instArgs{arg_fd, arg_fj}}, + // FRSQRT.D fd, fj + {mask: 0xfffffc00, value: 0x01146800, op: FRSQRT_D, args: instArgs{arg_fd, arg_fj}}, + // FRSQRT.S fd, fj + {mask: 0xfffffc00, value: 0x01146400, op: FRSQRT_S, args: instArgs{arg_fd, arg_fj}}, + // FSCALEB.D fd, fj, fk + {mask: 0xffff8000, value: 0x01110000, op: FSCALEB_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FSCALEB.S fd, fj, fk + {mask: 0xffff8000, value: 0x01108000, op: FSCALEB_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FSEL fd, fj, fk, ca + {mask: 0xfffc0000, value: 0x0d000000, op: FSEL, args: instArgs{arg_fd, arg_fj, arg_fk, arg_ca}}, + // FSQRT.D fd, fj + {mask: 0xfffffc00, value: 0x01144800, op: FSQRT_D, args: instArgs{arg_fd, arg_fj}}, + // FSQRT.S fd, fj + {mask: 0xfffffc00, value: 0x01144400, op: FSQRT_S, args: instArgs{arg_fd, arg_fj}}, + // FSTGT.D fd, rj, rk + {mask: 0xffff8000, value: 0x38768000, op: FSTGT_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FSTGT.S fd, rj, rk + {mask: 0xffff8000, value: 0x38760000, op: FSTGT_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FSTLE.D fd, rj, rk + {mask: 0xffff8000, value: 0x38778000, op: FSTLE_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FSTLE.S fd, rj, rk + {mask: 0xffff8000, value: 0x38770000, op: FSTLE_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FSTX.D fd, rj, rk + {mask: 0xffff8000, value: 0x383c0000, op: FSTX_D, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FSTX.S fd, rj, rk + {mask: 0xffff8000, value: 0x38380000, op: FSTX_S, args: instArgs{arg_fd, arg_rj, arg_rk}}, + // FST.D fd, rj, si12 + {mask: 0xffc00000, value: 0x2bc00000, op: FST_D, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}}, + // FST.S fd, rj, si12 + {mask: 0xffc00000, value: 0x2b400000, op: FST_S, args: instArgs{arg_fd, arg_rj, arg_si12_21_10}}, + // FSUB.D fd, fj, fk + {mask: 0xffff8000, value: 0x01030000, op: FSUB_D, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FSUB.S fd, fj, fk + {mask: 0xffff8000, value: 0x01028000, op: FSUB_S, args: instArgs{arg_fd, arg_fj, arg_fk}}, + // FTINTRM.L.D fd, fj + {mask: 0xfffffc00, value: 0x011a2800, op: FTINTRM_L_D, args: instArgs{arg_fd, arg_fj}}, + // FTINTRM.L.S fd, fj + {mask: 0xfffffc00, value: 0x011a2400, op: FTINTRM_L_S, args: instArgs{arg_fd, arg_fj}}, + // FTINTRM.W.D fd, fj + {mask: 0xfffffc00, value: 0x011a0800, op: FTINTRM_W_D, args: instArgs{arg_fd, arg_fj}}, + // FTINTRM.W.S fd, fj + {mask: 0xfffffc00, value: 0x011a0400, op: FTINTRM_W_S, args: instArgs{arg_fd, arg_fj}}, + // FTINTRNE.L.D fd, fj + {mask: 0xfffffc00, value: 0x011ae800, op: FTINTRNE_L_D, args: instArgs{arg_fd, arg_fj}}, + // FTINTRNE.L.S fd, fj + {mask: 0xfffffc00, value: 0x011ae400, op: FTINTRNE_L_S, args: instArgs{arg_fd, arg_fj}}, + // FTINTRNE.W.D fd, fj + {mask: 0xfffffc00, value: 0x011ac800, op: FTINTRNE_W_D, args: instArgs{arg_fd, arg_fj}}, + // FTINTRNE.W.S fd, fj + {mask: 0xfffffc00, value: 0x011ac400, op: FTINTRNE_W_S, args: instArgs{arg_fd, arg_fj}}, + // FTINTRP.L.D fd, fj + {mask: 0xfffffc00, value: 0x011a6800, op: FTINTRP_L_D, args: instArgs{arg_fd, arg_fj}}, + // FTINTRP.L.S fd, fj + {mask: 0xfffffc00, value: 0x011a6400, op: FTINTRP_L_S, args: instArgs{arg_fd, arg_fj}}, + // FTINTRP.W.D fd, fj + {mask: 0xfffffc00, value: 0x011a4800, op: FTINTRP_W_D, args: instArgs{arg_fd, arg_fj}}, + // FTINTRP.W.S fd, fj + {mask: 0xfffffc00, value: 0x011a4400, op: FTINTRP_W_S, args: instArgs{arg_fd, arg_fj}}, + // FTINTRZ.L.D fd, fj + {mask: 0xfffffc00, value: 0x011aa800, op: FTINTRZ_L_D, args: instArgs{arg_fd, arg_fj}}, + // FTINTRZ.L.S fd, fj + {mask: 0xfffffc00, value: 0x011aa400, op: FTINTRZ_L_S, args: instArgs{arg_fd, arg_fj}}, + // FTINTRZ.W.D fd, fj + {mask: 0xfffffc00, value: 0x011a8800, op: FTINTRZ_W_D, args: instArgs{arg_fd, arg_fj}}, + // FTINTRZ.W.S fd, fj + {mask: 0xfffffc00, value: 0x011a8400, op: FTINTRZ_W_S, args: instArgs{arg_fd, arg_fj}}, + // FTINT.L.D fd, fj + {mask: 0xfffffc00, value: 0x011b2800, op: FTINT_L_D, args: instArgs{arg_fd, arg_fj}}, + // FTINT.L.S fd, fj + {mask: 0xfffffc00, value: 0x011b2400, op: FTINT_L_S, args: instArgs{arg_fd, arg_fj}}, + // FTINT.W.D fd, fj + {mask: 0xfffffc00, value: 0x011b0800, op: FTINT_W_D, args: instArgs{arg_fd, arg_fj}}, + // FTINT.W.S fd, fj + {mask: 0xfffffc00, value: 0x011b0400, op: FTINT_W_S, args: instArgs{arg_fd, arg_fj}}, + // IBAR hint + {mask: 0xffff8000, value: 0x38728000, op: IBAR, args: instArgs{arg_hint_14_0}}, + // IDLE level + {mask: 0xffff8000, value: 0x06488000, op: IDLE, args: instArgs{arg_level_14_0}}, + // INVTLB op, rj, rk + {mask: 0xffff8000, value: 0x06498000, op: INVTLB, args: instArgs{arg_op_4_0, arg_rj, arg_rk}}, + // IOCSRRD.B rd, rj + {mask: 0xfffffc00, value: 0x06480000, op: IOCSRRD_B, args: instArgs{arg_rd, arg_rj}}, + // IOCSRRD.D rd, rj + {mask: 0xfffffc00, value: 0x06480c00, op: IOCSRRD_D, args: instArgs{arg_rd, arg_rj}}, + // IOCSRRD.H rd, rj + {mask: 0xfffffc00, value: 0x06480400, op: IOCSRRD_H, args: instArgs{arg_rd, arg_rj}}, + // IOCSRRD.W rd, rj + {mask: 0xfffffc00, value: 0x06480800, op: IOCSRRD_W, args: instArgs{arg_rd, arg_rj}}, + // IOCSRWR.B rd, rj + {mask: 0xfffffc00, value: 0x06481000, op: IOCSRWR_B, args: instArgs{arg_rd, arg_rj}}, + // IOCSRWR.D rd, rj + {mask: 0xfffffc00, value: 0x06481c00, op: IOCSRWR_D, args: instArgs{arg_rd, arg_rj}}, + // IOCSRWR.H rd, rj + {mask: 0xfffffc00, value: 0x06481400, op: IOCSRWR_H, args: instArgs{arg_rd, arg_rj}}, + // IOCSRWR.W rd, rj + {mask: 0xfffffc00, value: 0x06481800, op: IOCSRWR_W, args: instArgs{arg_rd, arg_rj}}, + // JIRL rd, rj, offs + {mask: 0xfc000000, value: 0x4c000000, op: JIRL, args: instArgs{arg_rd, arg_rj, arg_offset_15_0}}, + // LDDIR rd, rj, level + {mask: 0xfffc0000, value: 0x06400000, op: LDDIR, args: instArgs{arg_rd, arg_rj, arg_level_17_10}}, + // LDGT.B rd, rj, rk + {mask: 0xffff8000, value: 0x38780000, op: LDGT_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDGT.D rd, rj, rk + {mask: 0xffff8000, value: 0x38798000, op: LDGT_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDGT.H rd, rj, rk + {mask: 0xffff8000, value: 0x38788000, op: LDGT_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDGT.W rd, rj, rk + {mask: 0xffff8000, value: 0x38790000, op: LDGT_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDLE.B rd, rj, rk + {mask: 0xffff8000, value: 0x387a0000, op: LDLE_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDLE.D rd, rj, rk + {mask: 0xffff8000, value: 0x387b8000, op: LDLE_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDLE.H rd, rj, rk + {mask: 0xffff8000, value: 0x387a8000, op: LDLE_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDLE.W rd, rj, rk + {mask: 0xffff8000, value: 0x387b0000, op: LDLE_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDPTE rj, seq + {mask: 0xfffc001f, value: 0x06440000, op: LDPTE, args: instArgs{arg_rj, arg_seq_17_10}}, + // LDPTR.D rd, rj, si14 + {mask: 0xff000000, value: 0x26000000, op: LDPTR_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, + // LDPTR.W rd, rj, si14 + {mask: 0xff000000, value: 0x24000000, op: LDPTR_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, + // LDX.B rd, rj, rk + {mask: 0xffff8000, value: 0x38000000, op: LDX_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDX.BU rd, rj, rk + {mask: 0xffff8000, value: 0x38200000, op: LDX_BU, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDX.D rd, rj, rk + {mask: 0xffff8000, value: 0x380c0000, op: LDX_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDX.H rd, rj, rk + {mask: 0xffff8000, value: 0x38040000, op: LDX_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDX.HU rd, rj, rk + {mask: 0xffff8000, value: 0x38240000, op: LDX_HU, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDX.W rd, rj, rk + {mask: 0xffff8000, value: 0x38080000, op: LDX_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LDX.WU rd, rj, rk + {mask: 0xffff8000, value: 0x38280000, op: LDX_WU, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // LD.B rd, rj, si12 + {mask: 0xffc00000, value: 0x28000000, op: LD_B, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // LD.BU rd, rj, si12 + {mask: 0xffc00000, value: 0x2a000000, op: LD_BU, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // LD.D rd, rj, si12 + {mask: 0xffc00000, value: 0x28c00000, op: LD_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // LD.H rd, rj, si12 + {mask: 0xffc00000, value: 0x28400000, op: LD_H, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // LD.HU rd, rj, si12 + {mask: 0xffc00000, value: 0x2a400000, op: LD_HU, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // LD.W rd, rj, si12 + {mask: 0xffc00000, value: 0x28800000, op: LD_W, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // LD.WU rd, rj, si12 + {mask: 0xffc00000, value: 0x2a800000, op: LD_WU, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // LLACQ.D rd, rj + {mask: 0xfffffc00, value: 0x38578800, op: LLACQ_D, args: instArgs{arg_rd, arg_rj}}, + // LLACQ.W rd, rj + {mask: 0xfffffc00, value: 0x38578000, op: LLACQ_W, args: instArgs{arg_rd, arg_rj}}, + // LL.D rd, rj, si14 + {mask: 0xff000000, value: 0x22000000, op: LL_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, + // LL.W rd, rj, si14 + {mask: 0xff000000, value: 0x20000000, op: LL_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, + // LU12I.W rd, si20 + {mask: 0xfe000000, value: 0x14000000, op: LU12I_W, args: instArgs{arg_rd, arg_si20_24_5}}, + // LU32I.D rd, si20 + {mask: 0xfe000000, value: 0x16000000, op: LU32I_D, args: instArgs{arg_rd, arg_si20_24_5}}, + // LU52I.D rd, rj, si12 + {mask: 0xffc00000, value: 0x03000000, op: LU52I_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // MASKEQZ rd, rj, rk + {mask: 0xffff8000, value: 0x00130000, op: MASKEQZ, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MASKNEZ rd, rj, rk + {mask: 0xffff8000, value: 0x00138000, op: MASKNEZ, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MOD.D rd, rj, rk + {mask: 0xffff8000, value: 0x00228000, op: MOD_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MOD.DU rd, rj, rk + {mask: 0xffff8000, value: 0x00238000, op: MOD_DU, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MOD.W rd, rj, rk + {mask: 0xffff8000, value: 0x00208000, op: MOD_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MOD.WU rd, rj, rk + {mask: 0xffff8000, value: 0x00218000, op: MOD_WU, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MOVCF2FR fd, cj + {mask: 0xffffff00, value: 0x0114d400, op: MOVCF2FR, args: instArgs{arg_fd, arg_cj}}, + // MOVCF2GR rd, cj + {mask: 0xffffff00, value: 0x0114dc00, op: MOVCF2GR, args: instArgs{arg_rd, arg_cj}}, + // MOVFCSR2GR rd, fcsr + {mask: 0xfffffc00, value: 0x0114c800, op: MOVFCSR2GR, args: instArgs{arg_rd, arg_fcsr_9_5}}, + // MOVFR2CF cd, fj + {mask: 0xfffffc18, value: 0x0114d000, op: MOVFR2CF, args: instArgs{arg_cd, arg_fj}}, + // MOVFR2GR.D rd, fj + {mask: 0xfffffc00, value: 0x0114b800, op: MOVFR2GR_D, args: instArgs{arg_rd, arg_fj}}, + // MOVFR2GR.S rd, fj + {mask: 0xfffffc00, value: 0x0114b400, op: MOVFR2GR_S, args: instArgs{arg_rd, arg_fj}}, + // MOVFRH2GR.S rd, fj + {mask: 0xfffffc00, value: 0x0114bc00, op: MOVFRH2GR_S, args: instArgs{arg_rd, arg_fj}}, + // MOVGR2CF cd, rj + {mask: 0xfffffc18, value: 0x0114d800, op: MOVGR2CF, args: instArgs{arg_cd, arg_rj}}, + // MOVGR2FCSR fcsr, rj + {mask: 0xfffffc00, value: 0x0114c000, op: MOVGR2FCSR, args: instArgs{arg_fcsr_4_0, arg_rj}}, + // MOVGR2FRH.W fd, rj + {mask: 0xfffffc00, value: 0x0114ac00, op: MOVGR2FRH_W, args: instArgs{arg_fd, arg_rj}}, + // MOVGR2FR.D fd, rj + {mask: 0xfffffc00, value: 0x0114a800, op: MOVGR2FR_D, args: instArgs{arg_fd, arg_rj}}, + // MOVGR2FR.W fd, rj + {mask: 0xfffffc00, value: 0x0114a400, op: MOVGR2FR_W, args: instArgs{arg_fd, arg_rj}}, + // MULH.D rd, rj, rk + {mask: 0xffff8000, value: 0x001e0000, op: MULH_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MULH.DU rd, rj, rk + {mask: 0xffff8000, value: 0x001e8000, op: MULH_DU, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MULH.W rd, rj, rk + {mask: 0xffff8000, value: 0x001c8000, op: MULH_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MULH.WU rd, rj, rk + {mask: 0xffff8000, value: 0x001d0000, op: MULH_WU, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MULW.D.W rd, rj, rk + {mask: 0xffff8000, value: 0x001f0000, op: MULW_D_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MULW.D.WU rd, rj, rk + {mask: 0xffff8000, value: 0x001f8000, op: MULW_D_WU, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MUL.D rd, rj, rk + {mask: 0xffff8000, value: 0x001d8000, op: MUL_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // MUL.W rd, rj, rk + {mask: 0xffff8000, value: 0x001c0000, op: MUL_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // NOR rd, rj, rk + {mask: 0xffff8000, value: 0x00140000, op: NOR, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // OR rd, rj, rk + {mask: 0xffff8000, value: 0x00150000, op: OR, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // ORI rd, rj, ui12 + {mask: 0xffc00000, value: 0x03800000, op: ORI, args: instArgs{arg_rd, arg_rj, arg_ui12_21_10}}, + // ORN rd, rj, rk + {mask: 0xffff8000, value: 0x00160000, op: ORN, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // PCADDI rd, si20 + {mask: 0xfe000000, value: 0x18000000, op: PCADDI, args: instArgs{arg_rd, arg_si20_24_5}}, + // PCADDU12I rd, si20 + {mask: 0xfe000000, value: 0x1c000000, op: PCADDU12I, args: instArgs{arg_rd, arg_si20_24_5}}, + // PCADDU18I rd, si20 + {mask: 0xfe000000, value: 0x1e000000, op: PCADDU18I, args: instArgs{arg_rd, arg_si20_24_5}}, + // PCALAU12I rd, si20 + {mask: 0xfe000000, value: 0x1a000000, op: PCALAU12I, args: instArgs{arg_rd, arg_si20_24_5}}, + // PRELD hint, rj, si12 + {mask: 0xffc00000, value: 0x2ac00000, op: PRELD, args: instArgs{arg_hint_4_0, arg_rj, arg_si12_21_10}}, + // PRELDX hint, rj, rk + {mask: 0xffff8000, value: 0x382c0000, op: PRELDX, args: instArgs{arg_hint_4_0, arg_rj, arg_rk}}, + // RDTIMEH.W rd, rj + {mask: 0xfffffc00, value: 0x00006400, op: RDTIMEH_W, args: instArgs{arg_rd, arg_rj}}, + // RDTIMEL.W rd, rj + {mask: 0xfffffc00, value: 0x00006000, op: RDTIMEL_W, args: instArgs{arg_rd, arg_rj}}, + // RDTIME.D rd, rj + {mask: 0xfffffc00, value: 0x00006800, op: RDTIME_D, args: instArgs{arg_rd, arg_rj}}, + // REVB.2H rd, rj + {mask: 0xfffffc00, value: 0x00003000, op: REVB_2H, args: instArgs{arg_rd, arg_rj}}, + // REVB.2W rd, rj + {mask: 0xfffffc00, value: 0x00003800, op: REVB_2W, args: instArgs{arg_rd, arg_rj}}, + // REVB.4H rd, rj + {mask: 0xfffffc00, value: 0x00003400, op: REVB_4H, args: instArgs{arg_rd, arg_rj}}, + // REVB.D rd, rj + {mask: 0xfffffc00, value: 0x00003c00, op: REVB_D, args: instArgs{arg_rd, arg_rj}}, + // REVH.2W rd, rj + {mask: 0xfffffc00, value: 0x00004000, op: REVH_2W, args: instArgs{arg_rd, arg_rj}}, + // REVH.D rd, rj + {mask: 0xfffffc00, value: 0x00004400, op: REVH_D, args: instArgs{arg_rd, arg_rj}}, + // ROTRI.D rd, rj, ui6 + {mask: 0xffff0000, value: 0x004d0000, op: ROTRI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}}, + // ROTRI.W rd, rj, ui5 + {mask: 0xffff8000, value: 0x004c8000, op: ROTRI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}}, + // ROTR.D rd, rj, rk + {mask: 0xffff8000, value: 0x001b8000, op: ROTR_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // ROTR.W rd, rj, rk + {mask: 0xffff8000, value: 0x001b0000, op: ROTR_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // SCREL.D rd, rj + {mask: 0xfffffc00, value: 0x38578c00, op: SCREL_D, args: instArgs{arg_rd, arg_rj}}, + // SCREL.W rd, rj + {mask: 0xfffffc00, value: 0x38578400, op: SCREL_W, args: instArgs{arg_rd, arg_rj}}, + // SC.D rd, rj, si14 + {mask: 0xff000000, value: 0x23000000, op: SC_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, + // SC.Q rd, rk, rj + {mask: 0xffff8000, value: 0x38570000, op: SC_Q, args: instArgs{arg_rd, arg_rk, arg_rj}}, + // SC.W rd, rj, si14 + {mask: 0xff000000, value: 0x21000000, op: SC_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, + // SLLI.D rd, rj, ui6 + {mask: 0xffff0000, value: 0x00410000, op: SLLI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}}, + // SLLI.W rd, rj, ui5 + {mask: 0xffff8000, value: 0x00408000, op: SLLI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}}, + // SLL.D rd, rj, rk + {mask: 0xffff8000, value: 0x00188000, op: SLL_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // SLL.W rd, rj, rk + {mask: 0xffff8000, value: 0x00170000, op: SLL_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // SLT rd, rj, rk + {mask: 0xffff8000, value: 0x00120000, op: SLT, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // SLTI rd, rj, si12 + {mask: 0xffc00000, value: 0x02000000, op: SLTI, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // SLTU rd, rj, rk + {mask: 0xffff8000, value: 0x00128000, op: SLTU, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // SLTUI rd, rj, si12 + {mask: 0xffc00000, value: 0x02400000, op: SLTUI, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // SRAI.D rd, rj, ui6 + {mask: 0xffff0000, value: 0x00490000, op: SRAI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}}, + // SRAI.W rd, rj, ui5 + {mask: 0xffff8000, value: 0x00488000, op: SRAI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}}, + // SRA.D rd, rj, rk + {mask: 0xffff8000, value: 0x00198000, op: SRA_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // SRA.W rd, rj, rk + {mask: 0xffff8000, value: 0x00180000, op: SRA_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // SRLI.D rd, rj, ui6 + {mask: 0xffff0000, value: 0x00450000, op: SRLI_D, args: instArgs{arg_rd, arg_rj, arg_ui6_15_10}}, + // SRLI.W rd, rj, ui5 + {mask: 0xffff8000, value: 0x00448000, op: SRLI_W, args: instArgs{arg_rd, arg_rj, arg_ui5_14_10}}, + // SRL.D rd, rj, rk + {mask: 0xffff8000, value: 0x00190000, op: SRL_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // SRL.W rd, rj, rk + {mask: 0xffff8000, value: 0x00178000, op: SRL_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STGT.B rd, rj, rk + {mask: 0xffff8000, value: 0x387c0000, op: STGT_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STGT.D rd, rj, rk + {mask: 0xffff8000, value: 0x387d8000, op: STGT_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STGT.H rd, rj, rk + {mask: 0xffff8000, value: 0x387c8000, op: STGT_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STGT.W rd, rj, rk + {mask: 0xffff8000, value: 0x387d0000, op: STGT_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STLE.B rd, rj, rk + {mask: 0xffff8000, value: 0x387e0000, op: STLE_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STLE.D rd, rj, rk + {mask: 0xffff8000, value: 0x387f8000, op: STLE_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STLE.H rd, rj, rk + {mask: 0xffff8000, value: 0x387e8000, op: STLE_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STLE.W rd, rj, rk + {mask: 0xffff8000, value: 0x387f0000, op: STLE_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STPTR.D rd, rj, si14 + {mask: 0xff000000, value: 0x27000000, op: STPTR_D, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, + // STPTR.W rd, rj, si14 + {mask: 0xff000000, value: 0x25000000, op: STPTR_W, args: instArgs{arg_rd, arg_rj, arg_si14_23_10}}, + // STX.B rd, rj, rk + {mask: 0xffff8000, value: 0x38100000, op: STX_B, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STX.D rd, rj, rk + {mask: 0xffff8000, value: 0x381c0000, op: STX_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STX.H rd, rj, rk + {mask: 0xffff8000, value: 0x38140000, op: STX_H, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // STX.W rd, rj, rk + {mask: 0xffff8000, value: 0x38180000, op: STX_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // ST.B rd, rj, si12 + {mask: 0xffc00000, value: 0x29000000, op: ST_B, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // ST.D rd, rj, si12 + {mask: 0xffc00000, value: 0x29c00000, op: ST_D, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // ST.H rd, rj, si12 + {mask: 0xffc00000, value: 0x29400000, op: ST_H, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // ST.W rd, rj, si12 + {mask: 0xffc00000, value: 0x29800000, op: ST_W, args: instArgs{arg_rd, arg_rj, arg_si12_21_10}}, + // SUB.D rd, rj, rk + {mask: 0xffff8000, value: 0x00118000, op: SUB_D, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // SUB.W rd, rj, rk + {mask: 0xffff8000, value: 0x00110000, op: SUB_W, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // SYSCALL code + {mask: 0xffff8000, value: 0x002b0000, op: SYSCALL, args: instArgs{arg_code_14_0}}, + // TLBCLR + {mask: 0xffffffff, value: 0x06482000, op: TLBCLR, args: instArgs{}}, + // TLBFILL + {mask: 0xffffffff, value: 0x06483400, op: TLBFILL, args: instArgs{}}, + // TLBFLUSH + {mask: 0xffffffff, value: 0x06482400, op: TLBFLUSH, args: instArgs{}}, + // TLBRD + {mask: 0xffffffff, value: 0x06482c00, op: TLBRD, args: instArgs{}}, + // TLBSRCH + {mask: 0xffffffff, value: 0x06482800, op: TLBSRCH, args: instArgs{}}, + // TLBWR + {mask: 0xffffffff, value: 0x06483000, op: TLBWR, args: instArgs{}}, + // XOR rd, rj, rk + {mask: 0xffff8000, value: 0x00158000, op: XOR, args: instArgs{arg_rd, arg_rj, arg_rk}}, + // XORI rd, rj, ui12 + {mask: 0xffc00000, value: 0x03c00000, op: XORI, args: instArgs{arg_rd, arg_rj, arg_ui12_21_10}}, +}
diff --git a/loong64/loong64asm/testdata/gnucases.txt b/loong64/loong64asm/testdata/gnucases.txt new file mode 100644 index 0000000..2cfd5ea --- /dev/null +++ b/loong64/loong64asm/testdata/gnucases.txt
@@ -0,0 +1,415 @@ +ac391000| add.w $t0, $t1, $t2 +acb91000| add.d $t0, $t1, $t2 +ac41c002| addi.d $t0, $t1, 16 +ac01e002| addi.d $t0, $t1, -2048 +acfdff02| addi.d $t0, $t1, -1 +ac05e002| addi.d $t0, $t1, -2047 +acf9ff02| addi.d $t0, $t1, -2 +acfdff02| addi.d $t0, $t1, -1 +ac418002| addi.w $t0, $t1, 16 +ac410010| addu16i.d $t0, $t1, 16 +a4fcff13| addu16i.d $a0, $a1, -1 +acb92c00| alsl.d $t0, $t1, $t2, 0x2 +acb90400| alsl.w $t0, $t1, $t2, 0x2 +acb90600| alsl.wu $t0, $t1, $t2, 0x2 +ccb56138| amadd.d $t0, $t1, $t2 +cc356138| amadd.w $t0, $t1, $t2 +ccb56a38| amadd_db.d $t0, $t1, $t2 +cc356a38| amadd_db.w $t0, $t1, $t2 +ccb56238| amand.d $t0, $t1, $t2 +cc356238| amand.w $t0, $t1, $t2 +ccb56b38| amand_db.d $t0, $t1, $t2 +cc356b38| amand_db.w $t0, $t1, $t2 +ccb56538| ammax.d $t0, $t1, $t2 +ccb56738| ammax.du $t0, $t1, $t2 +cc356538| ammax.w $t0, $t1, $t2 +cc356738| ammax.wu $t0, $t1, $t2 +ccb56e38| ammax_db.d $t0, $t1, $t2 +ccb57038| ammax_db.du $t0, $t1, $t2 +cc356e38| ammax_db.w $t0, $t1, $t2 +cc357038| ammax_db.wu $t0, $t1, $t2 +ccb56638| ammin.d $t0, $t1, $t2 +ccb56838| ammin.du $t0, $t1, $t2 +cc356638| ammin.w $t0, $t1, $t2 +cc356838| ammin.wu $t0, $t1, $t2 +ccb56f38| ammin_db.d $t0, $t1, $t2 +ccb57138| ammin_db.du $t0, $t1, $t2 +cc356f38| ammin_db.w $t0, $t1, $t2 +cc357138| ammin_db.wu $t0, $t1, $t2 +ccb56338| amor.d $t0, $t1, $t2 +cc356338| amor.w $t0, $t1, $t2 +ccb56c38| amor_db.d $t0, $t1, $t2 +cc356c38| amor_db.w $t0, $t1, $t2 +ccb56038| amswap.d $t0, $t1, $t2 +cc356038| amswap.w $t0, $t1, $t2 +ccb56938| amswap_db.d $t0, $t1, $t2 +cc356938| amswap_db.w $t0, $t1, $t2 +ccb56438| amxor.d $t0, $t1, $t2 +cc356438| amxor.w $t0, $t1, $t2 +ccb56d38| amxor_db.d $t0, $t1, $t2 +cc356d38| amxor_db.w $t0, $t1, $t2 +acb91400| and $t0, $t1, $t2 +ac414003| andi $t0, $t1, 0x10 +acb91600| andn $t0, $t1, $t2 +00004003| nop +a0b90100| asrtgt.d $t1, $t2 +a0390100| asrtle.d $t1, $t2 +00100050| b 16 +20100048| bceqz $fcc1, 16 +20110048| bcnez $fcc1, 16 +1ff1ff4b| bcnez $fcc0, -16 +8d110058| beq $t0, $t1, 16 +a0110040| beqz $t1, 16 +9ff1ff43| beqz $t0, -16 +8d110064| bge $t0, $t1, 16 +8d11006c| bgeu $t0, $t1, 16 +ac490000| bitrev.4b $t0, $t1 +ac4d0000| bitrev.8b $t0, $t1 +ac550000| bitrev.d $t0, $t1 +ac510000| bitrev.w $t0, $t1 +00100054| bl 16 +8d110060| blt $t0, $t1, 16 +8d110068| bltu $t0, $t1, 16 +8d11005c| bne $t0, $t1, 16 +a0110044| bnez $t1, 16 +00002a00| break 0x0 +ac158a00| bstrins.d $t0, $t1, 0xa, 0x5 +ac156a00| bstrins.w $t0, $t1, 0xa, 0x5 +ac15ca00| bstrpick.d $t0, $t1, 0xa, 0x5 +ac956a00| bstrpick.w $t0, $t1, 0xa, 0x5 +ac390d00| bytepick.d $t0, $t1, $t2, 0x2 +ac390900| bytepick.w $t0, $t1, $t2, 0x2 +84010406| cacop 0x4, $t0, 256 +ac210000| clo.d $t0, $t1 +ac110000| clo.w $t0, $t1 +ac250000| clz.d $t0, $t1 +ac150000| clz.w $t0, $t1 +ac6d0000| cpucfg $t0, $t1 +ac392400| crc.w.b.w $t0, $t1, $t2 +acb92500| crc.w.d.w $t0, $t1, $t2 +acb92400| crc.w.h.w $t0, $t1, $t2 +ac392500| crc.w.w.w $t0, $t1, $t2 +ac392600| crcc.w.b.w $t0, $t1, $t2 +acb92700| crcc.w.d.w $t0, $t1, $t2 +acb92600| crcc.w.h.w $t0, $t1, $t2 +ac392700| crcc.w.w.w $t0, $t1, $t2 +0c040004| csrrd $t0, 0x1 +2c040004| csrwr $t0, 0x1 +ac050004| csrxchg $t0, $t1, 0x1 +ac290000| cto.d $t0, $t1 +ac190000| cto.w $t0, $t1 +ac2d0000| ctz.d $t0, $t1 +ac1d0000| ctz.w $t0, $t1 +00007238| dbar 0x0 +10802a00| dbcl 0x10 +ac392200| div.d $t0, $t1, $t2 +ac392300| div.du $t0, $t1, $t2 +ac392000| div.w $t0, $t1, $t2 +ac392100| div.wu $t0, $t1, $t2 +00384806| ertn +ac5d0000| ext.w.b $t0, $t1 +ac590000| ext.w.h $t0, $t1 +28091401| fabs.d $ft0, $ft1 +28051401| fabs.s $ft0, $ft1 +28250101| fadd.d $ft0, $ft1, $ft1 +28a50001| fadd.s $ft0, $ft1, $ft1 +28391401| fclass.d $ft0, $ft1 +28351401| fclass.s $ft0, $ft1 +2029200c| fcmp.caf.d $fcc0, $ft1, $ft2 +2029100c| fcmp.caf.s $fcc0, $ft1, $ft2 +2029220c| fcmp.ceq.d $fcc0, $ft1, $ft2 +2029120c| fcmp.ceq.s $fcc0, $ft1, $ft2 +2029230c| fcmp.cle.d $fcc0, $ft1, $ft2 +2029130c| fcmp.cle.s $fcc0, $ft1, $ft2 +2029210c| fcmp.clt.d $fcc0, $ft1, $ft2 +2029110c| fcmp.clt.s $fcc0, $ft1, $ft2 +2029280c| fcmp.cne.d $fcc0, $ft1, $ft2 +2029180c| fcmp.cne.s $fcc0, $ft1, $ft2 +20292a0c| fcmp.cor.d $fcc0, $ft1, $ft2 +20291a0c| fcmp.cor.s $fcc0, $ft1, $ft2 +2029260c| fcmp.cueq.d $fcc0, $ft1, $ft2 +2029160c| fcmp.cueq.s $fcc0, $ft1, $ft2 +2029270c| fcmp.cule.d $fcc0, $ft1, $ft2 +2029170c| fcmp.cule.s $fcc0, $ft1, $ft2 +2029250c| fcmp.cult.d $fcc0, $ft1, $ft2 +2029150c| fcmp.cult.s $fcc0, $ft1, $ft2 +20292c0c| fcmp.cune.d $fcc0, $ft1, $ft2 +20291c0c| fcmp.cune.s $fcc0, $ft1, $ft2 +2029240c| fcmp.cun.d $fcc0, $ft1, $ft2 +2029140c| fcmp.cun.s $fcc0, $ft1, $ft2 +20a9200c| fcmp.saf.d $fcc0, $ft1, $ft2 +20a9100c| fcmp.saf.s $fcc0, $ft1, $ft2 +20a9220c| fcmp.seq.d $fcc0, $ft1, $ft2 +20a9120c| fcmp.seq.s $fcc0, $ft1, $ft2 +20a9230c| fcmp.sle.d $fcc0, $ft1, $ft2 +20a9130c| fcmp.sle.s $fcc0, $ft1, $ft2 +20a9210c| fcmp.slt.d $fcc0, $ft1, $ft2 +20a9110c| fcmp.slt.s $fcc0, $ft1, $ft2 +20a9280c| fcmp.sne.d $fcc0, $ft1, $ft2 +20a9180c| fcmp.sne.s $fcc0, $ft1, $ft2 +20a92a0c| fcmp.sor.d $fcc0, $ft1, $ft2 +20a91a0c| fcmp.sor.s $fcc0, $ft1, $ft2 +20a9260c| fcmp.sueq.d $fcc0, $ft1, $ft2 +20a9160c| fcmp.sueq.s $fcc0, $ft1, $ft2 +20a9270c| fcmp.sule.d $fcc0, $ft1, $ft2 +20a9170c| fcmp.sule.s $fcc0, $ft1, $ft2 +20a9250c| fcmp.sult.d $fcc0, $ft1, $ft2 +20a9150c| fcmp.sult.s $fcc0, $ft1, $ft2 +20a92c0c| fcmp.sune.d $fcc0, $ft1, $ft2 +20a91c0c| fcmp.sune.s $fcc0, $ft1, $ft2 +20a9240c| fcmp.sun.d $fcc0, $ft1, $ft2 +20a9140c| fcmp.sun.s $fcc0, $ft1, $ft2 +28291301| fcopysign.d $ft0, $ft1, $ft2 +28a91201| fcopysign.s $ft0, $ft1, $ft2 +28251901| fcvt.d.s $ft0, $ft1 +28191901| fcvt.s.d $ft0, $ft1 +28290701| fdiv.d $ft0, $ft1, $ft2 +28a90601| fdiv.s $ft0, $ft1, $ft2 +28291d01| ffint.d.l $ft0, $ft1 +28211d01| ffint.d.w $ft0, $ft1 +28191d01| ffint.s.l $ft0, $ft1 +28111d01| ffint.s.w $ft0, $ft1 +a841802b| fld.d $ft0, $t1, 16 +a841002b| fld.s $ft0, $t1, 16 +a8b97438| fldgt.d $ft0, $t1, $t2 +a8397438| fldgt.s $ft0, $t1, $t2 +a8b97538| fldle.d $ft0, $t1, $t2 +a8397538| fldle.s $ft0, $t1, $t2 +a8393438| fldx.d $ft0, $t1, $t2 +a8393038| fldx.s $ft0, $t1, $t2 +28291401| flogb.d $ft0, $ft1 +28251401| flogb.s $ft0, $ft1 +28a92508| fmadd.d $ft0, $ft1, $ft2, $ft3 +28a91508| fmadd.s $ft0, $ft1, $ft2, $ft3 +28290901| fmax.d $ft0, $ft1, $ft2 +28a90801| fmax.s $ft0, $ft1, $ft2 +28290d01| fmaxa.d $ft0, $ft1, $ft2 +28a90c01| fmaxa.s $ft0, $ft1, $ft2 +28290b01| fmin.d $ft0, $ft1, $ft2 +28a90a01| fmin.s $ft0, $ft1, $ft2 +28290f01| fmina.d $ft0, $ft1, $ft2 +28a90e01| fmina.s $ft0, $ft1, $ft2 +48991401| fmov.d $ft0, $ft2 +48951401| fmov.s $ft0, $ft2 +28a96508| fmsub.d $ft0, $ft1, $ft2, $ft3 +28a95508| fmsub.s $ft0, $ft1, $ft2, $ft3 +28290501| fmul.d $ft0, $ft1, $ft2 +28a90401| fmul.s $ft0, $ft1, $ft2 +28191401| fneg.d $ft0, $ft1 +28151401| fneg.s $ft0, $ft1 +28a9a508| fnmadd.d $ft0, $ft1, $ft2, $ft3 +28a99508| fnmadd.s $ft0, $ft1, $ft2, $ft3 +28a9e508| fnmsub.d $ft0, $ft1, $ft2, $ft3 +28a9d508| fnmsub.s $ft0, $ft1, $ft2, $ft3 +28591401| frecip.d $ft0, $ft1 +28551401| frecip.s $ft0, $ft1 +28491e01| frint.d $ft0, $ft1 +28451e01| frint.s $ft0, $ft1 +28691401| frsqrt.d $ft0, $ft1 +28651401| frsqrt.s $ft0, $ft1 +28291101| fscaleb.d $ft0, $ft1, $ft2 +28a91001| fscaleb.s $ft0, $ft1, $ft2 +28a9000d| fsel $ft0, $ft1, $ft2, $fcc1 +28491401| fsqrt.d $ft0, $ft1 +28451401| fsqrt.s $ft0, $ft1 +a841c02b| fst.d $ft0, $t1, 16 +a841402b| fst.s $ft0, $t1, 16 +a8b97638| fstgt.d $ft0, $t1, $t2 +a8397638| fstgt.s $ft0, $t1, $t2 +a8b97738| fstle.d $ft0, $t1, $t2 +a8397738| fstle.s $ft0, $t1, $t2 +a8393c38| fstx.d $ft0, $t1, $t2 +a8393838| fstx.s $ft0, $t1, $t2 +28290301| fsub.d $ft0, $ft1, $ft2 +28a90201| fsub.s $ft0, $ft1, $ft2 +28291b01| ftint.l.d $ft0, $ft1 +28251b01| ftint.l.s $ft0, $ft1 +28091b01| ftint.w.d $ft0, $ft1 +28051b01| ftint.w.s $ft0, $ft1 +28291a01| ftintrm.l.d $ft0, $ft1 +28251a01| ftintrm.l.s $ft0, $ft1 +28091a01| ftintrm.w.d $ft0, $ft1 +28051a01| ftintrm.w.s $ft0, $ft1 +28e91a01| ftintrne.l.d $ft0, $ft1 +28e51a01| ftintrne.l.s $ft0, $ft1 +28c91a01| ftintrne.w.d $ft0, $ft1 +28c51a01| ftintrne.w.s $ft0, $ft1 +28691a01| ftintrp.l.d $ft0, $ft1 +28651a01| ftintrp.l.s $ft0, $ft1 +28491a01| ftintrp.w.d $ft0, $ft1 +28451a01| ftintrp.w.s $ft0, $ft1 +28a91a01| ftintrz.l.d $ft0, $ft1 +28a51a01| ftintrz.l.s $ft0, $ft1 +28891a01| ftintrz.w.d $ft0, $ft1 +28851a01| ftintrz.w.s $ft0, $ft1 +00807238| ibar 0x0 +10804806| idle 0x10 +ac014806| iocsrrd.b $t0, $t1 +ac054806| iocsrrd.h $t0, $t1 +ac094806| iocsrrd.w $t0, $t1 +ac0d4806| iocsrrd.d $t0, $t1 +ac114806| iocsrwr.b $t0, $t1 +ac154806| iocsrwr.h $t0, $t1 +ac194806| iocsrwr.w $t0, $t1 +ac1d4806| iocsrwr.d $t0, $t1 +82b54906| invtlb 0x2, $t0, $t1 +ac11004c| jirl $t0, $t1, 16 +ac410028| ld.b $t0, $t1, 16 +ac41002a| ld.bu $t0, $t1, 16 +ac41c028| ld.d $t0, $t1, 16 +ac414028| ld.h $t0, $t1, 16 +ac41402a| ld.hu $t0, $t1, 16 +ac418028| ld.w $t0, $t1, 16 +ac41802a| ld.wu $t0, $t1, 16 +ac414006| lddir $t0, $t1, 0x10 +ac397838| ldgt.b $t0, $t1, $t2 +acb97938| ldgt.d $t0, $t1, $t2 +acb97838| ldgt.h $t0, $t1, $t2 +ac397938| ldgt.w $t0, $t1, $t2 +ac397a38| ldle.b $t0, $t1, $t2 +acb97b38| ldle.d $t0, $t1, $t2 +acb97a38| ldle.h $t0, $t1, $t2 +ac397b38| ldle.w $t0, $t1, $t2 +ac110026| ldptr.d $t0, $t1, 16 +ac01e024| ldptr.w $t0, $t1, -8192 +ac05f024| ldptr.w $t0, $t1, -4092 +acfd1f24| ldptr.w $t0, $t1, 8188 +acfdff24| ldptr.w $t0, $t1, -4 +ac050024| ldptr.w $t0, $t1, 4 +ac110024| ldptr.w $t0, $t1, 16 +80094406| ldpte $t0, 0x2 +ac390038| ldx.b $t0, $t1, $t2 +ac392038| ldx.bu $t0, $t1, $t2 +ac390c38| ldx.d $t0, $t1, $t2 +ac390438| ldx.h $t0, $t1, $t2 +ac392438| ldx.hu $t0, $t1, $t2 +ac390838| ldx.w $t0, $t1, $t2 +ac392838| ldx.wu $t0, $t1, $t2 +ac110022| ll.d $t0, $t1, 16 +ac110020| ll.w $t0, $t1, 16 +0c020014| lu12i.w $t0, 16 +0c000015| lu12i.w $t0, -524288 +ecffff15| lu12i.w $t0, -1 +ecffff14| lu12i.w $t0, 524287 +0c020016| lu32i.d $t0, 16 +ac410003| lu52i.d $t0, $t1, 16 +ac391300| maskeqz $t0, $t1, $t2 +acb91300| masknez $t0, $t1, $t2 +acb92200| mod.d $t0, $t1, $t2 +acb92300| mod.du $t0, $t1, $t2 +acb92000| mod.w $t0, $t1, $t2 +acb92100| mod.wu $t0, $t1, $t2 +28d41401| movcf2fr $ft0, $fcc1 +2cdc1401| movcf2gr $t0, $fcc1 +0cc81401| movfcsr2gr $t0, $fcsr0 +20d11401| movfr2cf $fcc0, $ft1 +2cb91401| movfr2gr.d $t0, $ft1 +2cb51401| movfr2gr.s $t0, $ft1 +2cbd1401| movfrh2gr.s $t0, $ft1 +a0d91401| movgr2cf $fcc0, $t1 +80c11401| movgr2fcsr $fcsr0, $t0 +a8a91401| movgr2fr.d $ft0, $t1 +a8a51401| movgr2fr.w $ft0, $t1 +a8ad1401| movgr2frh.w $ft0, $t1 +acb91d00| mul.d $t0, $t1, $t2 +ac391c00| mul.w $t0, $t1, $t2 +ac391e00| mulh.d $t0, $t1, $t2 +acb91e00| mulh.du $t0, $t1, $t2 +acb91c00| mulh.w $t0, $t1, $t2 +ac391d00| mulh.wu $t0, $t1, $t2 +ac391f00| mulw.d.w $t0, $t1, $t2 +acb91f00| mulw.d.wu $t0, $t1, $t2 +ac391400| nor $t0, $t1, $t2 +ac391500| or $t0, $t1, $t2 +ac418003| ori $t0, $t1, 0x10 +ac391600| orn $t0, $t1, $t2 +0c020018| pcaddi $t0, 16 +0c02001c| pcaddu12i $t0, 16 +0c02001e| pcaddu18i $t0, 16 +0c02001a| pcalau12i $t0, 16 +a041c02a| preld 0x0, $t1, 16 +a0392c38| preldx 0x0, $t1, $t2 +ac690000| rdtime.d $t0, $t1 +ac650000| rdtimeh.w $t0, $t1 +ac610000| rdtimel.w $t0, $t1 +ac310000| revb.2h $t0, $t1 +ac390000| revb.2w $t0, $t1 +ac350000| revb.4h $t0, $t1 +ac3d0000| revb.d $t0, $t1 +ac410000| revh.2w $t0, $t1 +ac450000| revh.d $t0, $t1 +acb91b00| rotr.d $t0, $t1, $t2 +ac391b00| rotr.w $t0, $t1, $t2 +ac414d00| rotri.d $t0, $t1, 0x10 +acc14c00| rotri.w $t0, $t1, 0x10 +ac110023| sc.d $t0, $t1, 16 +ac110021| sc.w $t0, $t1, 16 +acb91800| sll.d $t0, $t1, $t2 +ac391700| sll.w $t0, $t1, $t2 +ac414100| slli.d $t0, $t1, 0x10 +acc14000| slli.w $t0, $t1, 0x10 +ac391200| slt $t0, $t1, $t2 +ac410002| slti $t0, $t1, 16 +acb91200| sltu $t0, $t1, $t2 +ac414002| sltui $t0, $t1, 16 +acb91900| sra.d $t0, $t1, $t2 +ac391800| sra.w $t0, $t1, $t2 +ac414900| srai.d $t0, $t1, 0x10 +acc14800| srai.w $t0, $t1, 0x10 +ac391900| srl.d $t0, $t1, $t2 +acb91700| srl.w $t0, $t1, $t2 +ac414500| srli.d $t0, $t1, 0x10 +acc14400| srli.w $t0, $t1, 0x10 +ac410029| st.b $t0, $t1, 16 +ac41c029| st.d $t0, $t1, 16 +ac414029| st.h $t0, $t1, 16 +ac418029| st.w $t0, $t1, 16 +ac397c38| stgt.b $t0, $t1, $t2 +acb97d38| stgt.d $t0, $t1, $t2 +acb97c38| stgt.h $t0, $t1, $t2 +ac397d38| stgt.w $t0, $t1, $t2 +ac397e38| stle.b $t0, $t1, $t2 +acb97f38| stle.d $t0, $t1, $t2 +acb97e38| stle.h $t0, $t1, $t2 +ac397f38| stle.w $t0, $t1, $t2 +ac110027| stptr.d $t0, $t1, 16 +ac110025| stptr.w $t0, $t1, 16 +ac391038| stx.b $t0, $t1, $t2 +ac391c38| stx.d $t0, $t1, $t2 +ac391438| stx.h $t0, $t1, $t2 +ac391838| stx.w $t0, $t1, $t2 +acb91100| sub.d $t0, $t1, $t2 +ac391100| sub.w $t0, $t1, $t2 +00002b00| syscall 0x0 +00204806| tlbclr +00344806| tlbfill +00244806| tlbflush +002c4806| tlbrd +00284806| tlbsrch +00304806| tlbwr +acb91500| xor $t0, $t1, $t2 +ac41c003| xori $t0, $t1, 0x10 +cc355d38| amadd.b $t0, $t1, $t2 +cc355f38| amadd_db.b $t0, $t1, $t2 +ccb55f38| amadd_db.h $t0, $t1, $t2 +ccb55d38| amadd.h $t0, $t1, $t2 +cc355838| amcas.b $t0, $t1, $t2 +ccb55938| amcas.d $t0, $t1, $t2 +cc355a38| amcas_db.b $t0, $t1, $t2 +ccb55b38| amcas_db.d $t0, $t1, $t2 +ccb55a38| amcas_db.h $t0, $t1, $t2 +cc355b38| amcas_db.w $t0, $t1, $t2 +ccb55838| amcas.h $t0, $t1, $t2 +cc355938| amcas.w $t0, $t1, $t2 +cc355c38| amswap.b $t0, $t1, $t2 +cc355e38| amswap_db.b $t0, $t1, $t2 +ccb55e38| amswap_db.h $t0, $t1, $t2 +ccb55c38| amswap.h $t0, $t1, $t2 +28791401| frecipe.d $ft0, $ft1 +28751401| frecipe.s $ft0, $ft1 +28891401| frsqrte.d $ft0, $ft1 +28851401| frsqrte.s $ft0, $ft1 +ac895738| llacq.d $t0, $t1 +ac815738| llacq.w $t0, $t1 +ac8d5738| screl.d $t0, $t1 +ac855738| screl.w $t0, $t1
diff --git a/loong64/loong64asm/testdata/plan9cases.txt b/loong64/loong64asm/testdata/plan9cases.txt new file mode 100644 index 0000000..53f5d45 --- /dev/null +++ b/loong64/loong64asm/testdata/plan9cases.txt
@@ -0,0 +1,365 @@ +a6101000| ADD R4, R5, R6 +a6901000| ADDV R4, R5, R6 +a5101000| ADD R4, R5 +a5901000| ADDV R4, R5 +85fcbf02| ADD $-1, R4, R5 +84fcbf02| ADD $-1, R4 +85fcff02| ADDV $-1, R4, R5 +84fcff02| ADDV $-1, R4 +ac391000| ADD R14, R13, R12 +acb91000| ADDV R14, R13, R12 +ac41c002| ADDV $16, R13, R12 +ac01e002| ADDV $-2048, R13, R12 +acfdff02| ADDV $-1, R13, R12 +ac05e002| ADDV $-2047, R13, R12 +acf9ff02| ADDV $-2, R13, R12 +ac418002| ADD $16, R13, R12 +a6101100| SUB R4, R5, R6 +a6901100| SUBV R4, R5, R6 +a5101100| SUB R4, R5 +a5901100| SUBV R4, R5 +05101100| NEGW R4, R5 +05901100| NEGV R4, R5 +84781200| SGT R30, R4 +85781200| SGT R30, R4, R5 +84f81200| SGTU R30, R4 +85f81200| SGTU R30, R4, R5 +a6901400| AND R4, R5, R6 +a5901400| AND R4, R5 +85044003| AND $1, R4, R5 +84044003| AND $1, R4 +a5101c00| MUL R4, R5 +a6101c00| MUL R4, R5, R6 +a5901d00| MULV R4, R5 +a6901d00| MULV R4, R5, R6 +a5101e00| MULHV R4, R5 +a6101e00| MULHV R4, R5, R6 +a5901e00| MULHVU R4, R5 +a6901e00| MULHVU R4, R5, R6 +28290501| MULD F10, F9, F8 +28a90401| MULF F10, F9, F8 +a5102000| DIV R4, R5 +a6102000| DIV R4, R5, R6 +a5102100| DIVU R4, R5 +a6102100| DIVU R4, R5, R6 +a5102200| DIVV R4, R5 +a6102200| DIVV R4, R5, R6 +a5102300| DIVVU R4, R5 +a6102300| DIVVU R4, R5, R6 +28290701| DIVD F10, F9, F8 +28a90601| DIVF F10, F9, F8 +a5902000| REM R4, R5 +a6902000| REM R4, R5, R6 +a5902100| REMU R4, R5 +a6902100| REMU R4, R5, R6 +a5902200| REMV R4, R5 +a6902200| REMV R4, R5, R6 +a5902300| REMVU R4, R5 +a6902300| REMVU R4, R5, R6 +04020014| LU12IW $16, R4 +24000014| LU12IW $1, R4 +85001700| MOVW R4, R5 +85001500| MOVV R4, R5 +85fc4303| MOVBU R4, R5 +1e020014| LU12IW $16, R30 +85781000| ADD R30, R4, R5 +de038003| OR $0, R30 +ac391400| NOR R14, R13, R12 +acb91500| XOR R14, R13, R12 +ac41c003| XOR $16, R13, R12 +85f81000| ADDV R30, R4, R5 +8500cf00| MOVHU R4, R5 +a5101700| SLL R4, R5 +a6101700| SLL R4, R5, R6 +a5901700| SRL R4, R5 +a6901700| SRL R4, R5, R6 +a5101800| SRA R4, R5 +a6101800| SRA R4, R5, R6 +a5101b00| ROTR R4, R5 +a6101b00| ROTR R4, R5, R6 +a5901800| SLLV R4, R5 +a6901800| SLLV R4, R5, R6 +a5901b00| ROTRV R4, R5 +a6901b00| ROTRV R4, R5, R6 +85904000| SLL $4, R4, R5 +84904000| SLL $4, R4 +85904400| SRL $4, R4, R5 +84904400| SRL $4, R4 +85904800| SRA $4, R4, R5 +84904800| SRA $4, R4 +85904c00| ROTR $4, R4, R5 +84904c00| ROTR $4, R4 +85104100| SLLV $4, R4, R5 +84104100| SLLV $4, R4 +85104d00| ROTRV $4, R4, R5 +84104d00| ROTRV $4, R4 +a6101300| MASKEQZ R4, R5, R6 +a6901300| MASKNEZ R4, R5, R6 +00050048| BFPT 1(PC) +00040048| BFPF 1(PC) +80040058| BEQ R4, 1(PC) +8d110058| BEQ R12, R13, 4(PC) +a0110040| BEQ R13, 4(PC) +9ff1ff43| BEQ R12, -4(PC) +8504005c| BNE R4, R5, 1(PC) +8004005c| BNE R4, 1(PC) +8004005c| BNE R4, 1(PC) +a0140058| BEQ R5, 5(PC) +a0110058| BEQ R13, 4(PC) +00ebff5f| BNE R24, -6(PC) +801d005c| BNE R12, 7(PC) +85040060| BLT R4, R5, 1(PC) +80fcff63| BLTZ R4, -1(PC) +05040060| BGTZ R5, 1(PC) +80040060| BLTZ R4, 1(PC) +47d5ff6b| BLTU R10, R7, -11(PC) +802c0068| BLTU R4, 11(PC) +85040064| BGE R4, R5, 1(PC) +80fcff67| BGEZ R4, -1(PC) +47d5ff6f| BGEU R10, R7, -11(PC) +802c006c| BGEU R4, 11(PC) +04d8ff67| BLEZ R4, -10(PC) +00040058| JMP 1(PC) +8000004c| JMP (R4) +00340050| JMP 13(PC) +00100050| JMP 4(PC) +00100054| CALL 4(PC) +8100004c| CALL (R4) +00140054| CALL 5(PC) +a4048029| MOVW R4, 1(R5) +a404c029| MOVV R4, 1(R5) +a4040029| MOVB R4, 1(R5) +ac410029| MOVB R12, 16(R13) +a4040021| SC R4, 1(R5) +a4040023| SCV R4, 1(R5) +a4040028| MOVB 1(R5), R4 +a404002a| MOVBU 1(R5), R4 +a4044028| MOVH 1(R5), R4 +a404402a| MOVHU 1(R5), R4 +a4048028| MOVW 1(R5), R4 +a404802a| MOVWU 1(R5), R4 +a404c028| MOVV 1(R5), R4 +a4040020| LL 1(R5), R4 +a4040022| LLV 1(R5), R4 +a4fc3f20| LL -1(R5), R4 +a4fc3f22| LLV -1(R5), R4 +00002a00| BREAK +00007238| DBAR +00002b00| SYSCALL +00004003| NOOP +a5900001| ADDF F4, F5 +a6900001| ADDF F4, F5, F6 +28a50001| ADDF F9, F9, F8 +28250101| ADDD F9, F9, F8 +85041401| ABSF F4, F5 +85081401| ABSD F4, F5 +85141401| NEGF F4, F5 +85181401| NEGD F4, F5 +85441401| SQRTF F4, F5 +85481401| SQRTD F4, F5 +a090110c| CMPGTF F4, F5, FCC0 +a090210c| CMPGTD F4, F5, FCC0 +a090130c| CMPGEF F4, F5, FCC0 +a090230c| CMPGED F4, F5, FCC0 +a010220c| CMPEQD F4, F5, FCC0 +2029120c| CMPEQF F10, F9, FCC0 +85241901| MOVFD F4, F5 +85181901| MOVDF F4, F5 +85101d01| FFINTFW F4, F5 +85201d01| FFINTDW F4, F5 +85181d01| FFINTFV F4, F5 +85281d01| FFINTDV F4, F5 +85041b01| FTINTWF F4, F5 +85241b01| FTINTVF F4, F5 +85081b01| FTINTWD F4, F5 +85281b01| FTINTVD F4, F5 +85881a01| FTINTRZWD F4, F5 +85841a01| FTINTRZWF F4, F5 +85a81a01| FTINTRZVD F4, F5 +85a41a01| FTINTRZVF F4, F5 +85941401| MOVF F4, F5 +85981401| MOVD F4, F5 +85a41401| MOVW R4, F5 +85b41401| MOVW F4, R5 +85a81401| MOVV R4, F5 +85b81401| MOVV F4, R5 +04dc1401| MOVV FCC0, R4 +80d81401| MOVV R4, FCC0 +6440002b| MOVF 16(R3), F4 +6440802b| MOVD 16(R3), F4 +a404002b| MOVF 1(R5), F4 +a404802b| MOVD 1(R5), F4 +6460402b| MOVF F4, 24(R3) +6460c02b| MOVD F4, 24(R3) +a404402b| MOVF F4, 1(R5) +a404c02b| MOVD F4, 1(R5) +5e020014| LU12IW $18, R30 +64a95214| LU12IW $169291, R4 +84d08703| OR $500, R4 +84428614| LU12IW $274964, R4 +84848c03| OR $801, R4 +24640816| LU32ID $17185, R4 +84000003| LU52ID $0, R4 +24a93615| LU12IW $-412343, R4 +84849003| OR $1057, R4 +8464c817| LU32ID $-113884, R4 +848c0203| LU52ID $163, R4 +80600000| RDTIMELW R4, R0 +80640000| RDTIMEHW R4, R0 +85680000| RDTIMED R4, R5 +1e00001a| PCALAU12I $0, R30 +0c02001c| PCADDU12I $16, R12 +c4038029| MOVW R4, 0(R30) +ac395c38| AMSWAPB R14, (R13), R12 +acb95c38| AMSWAPH R14, (R13), R12 +ac396038| AMSWAPW R14, (R13), R12 +acb96038| AMSWAPV R14, (R13), R12 +ac395838| AMCASB R14, (R13), R12 +acb95838| AMCASH R14, (R13), R12 +ac395938| AMCASW R14, (R13), R12 +acb95938| AMCASV R14, (R13), R12 +ac396138| AMADDW R14, (R13), R12 +acb96138| AMADDV R14, (R13), R12 +ac396238| AMANDW R14, (R13), R12 +acb96238| AMANDV R14, (R13), R12 +ac396338| AMORW R14, (R13), R12 +acb96338| AMORV R14, (R13), R12 +ac396438| AMXORW R14, (R13), R12 +acb96438| AMXORV R14, (R13), R12 +ac396538| AMMAXW R14, (R13), R12 +acb96538| AMMAXV R14, (R13), R12 +ac396638| AMMINW R14, (R13), R12 +acb96638| AMMINV R14, (R13), R12 +ac396738| AMMAXWU R14, (R13), R12 +acb96738| AMMAXVU R14, (R13), R12 +ac396838| AMMINWU R14, (R13), R12 +acb96838| AMMINVU R14, (R13), R12 +ac395e38| AMSWAPDBB R14, (R13), R12 +acb95e38| AMSWAPDBH R14, (R13), R12 +ac396938| AMSWAPDBW R14, (R13), R12 +acb96938| AMSWAPDBV R14, (R13), R12 +ac395a38| AMCASDBB R14, (R13), R12 +acb95a38| AMCASDBH R14, (R13), R12 +ac395b38| AMCASDBW R14, (R13), R12 +acb95b38| AMCASDBV R14, (R13), R12 +ac396a38| AMADDDBW R14, (R13), R12 +acb96a38| AMADDDBV R14, (R13), R12 +ac396b38| AMANDDBW R14, (R13), R12 +acb96b38| AMANDDBV R14, (R13), R12 +ac396c38| AMORDBW R14, (R13), R12 +acb96c38| AMORDBV R14, (R13), R12 +ac396d38| AMXORDBW R14, (R13), R12 +acb96d38| AMXORDBV R14, (R13), R12 +ac396e38| AMMAXDBW R14, (R13), R12 +acb96e38| AMMAXDBV R14, (R13), R12 +ac396f38| AMMINDBW R14, (R13), R12 +acb96f38| AMMINDBV R14, (R13), R12 +ac397038| AMMAXDBWU R14, (R13), R12 +acb97038| AMMAXDBVU R14, (R13), R12 +ac397138| AMMINDBWU R14, (R13), R12 +acb97138| AMMINDBVU R14, (R13), R12 +856c0000| CPUCFG R4, R5 +85481e01| FRINTD F4, F5 +83c01401| MOVV R4, FCSR3 +64c81401| MOVV FCSR3, R4 +80d01401| MOVV F4, FCC0 +04d41401| MOVV FCC0, F4 +a6901201| FCOPYSGF F4, F5, F6 +a6101301| FCOPYSGD F4, F5, F6 +85500000| BITREVW R4, R5 +85540000| BITREVV R4, R5 +a6102400| CRCWBW R4, R5, R6 +a6902400| CRCWHW R4, R5, R6 +a6102500| CRCWWW R4, R5, R6 +a6902500| CRCWVW R4, R5, R6 +a6102600| CRCCWBW R4, R5, R6 +a6902600| CRCCWHW R4, R5, R6 +a6102700| CRCCWWW R4, R5, R6 +a6902700| CRCCWVW R4, R5, R6 +cc350038| MOVB (R14)(R13), R12 +cc352038| MOVBU (R14)(R13), R12 +cc350438| MOVH (R14)(R13), R12 +cc352438| MOVHU (R14)(R13), R12 +cc350838| MOVW (R14)(R13), R12 +cc352838| MOVWU (R14)(R13), R12 +cc350c38| MOVV (R14)(R13), R12 +cc351038| MOVB R12, (R14)(R13) +cc351438| MOVH R12, (R14)(R13) +cc351838| MOVW R12, (R14)(R13) +cc351c38| MOVV R12, (R14)(R13) +c2353038| MOVF (R14)(R13), F2 +c2353438| MOVD (R14)(R13), F2 +c2353838| MOVF F2, (R14)(R13) +c2353c38| MOVD F2, (R14)(R13) +a010120c| CMPEQF F4, F5, FCC0 +a190110c| CMPGTF F4, F5, FCC1 +a290210c| CMPGTD F4, F5, FCC2 +a390130c| CMPGEF F4, F5, FCC3 +a490230c| CMPGED F4, F5, FCC4 +a510220c| CMPEQD F4, F5, FCC5 +85100000| CLOW R4, R5 +85200000| CLOV R4, R5 +85140000| CLZW R4, R5 +85240000| CLZV R4, R5 +85180000| CTOW R4, R5 +85280000| CTOV R4, R5 +851c0000| CTZW R4, R5 +852c0000| CTZV R4, R5 +853c0000| REVBV R4, R5 +85380000| REVB2W R4, R5 +85340000| REVB4H R4, R5 +85300000| REVB2H R4, R5 +a6900a01| FMINF F4, F5, F6 +a5900a01| FMINF F4, F5 +a6100b01| FMIND F4, F5, F6 +a5100b01| FMIND F4, F5 +a6900801| FMAXF F4, F5, F6 +a5900801| FMAXF F4, F5 +a6100901| FMAXD F4, F5, F6 +a5100901| FMAXD F4, F5 +85341401| FCLASSF F4, F5 +85381401| FCLASSD F4, F5 +02041a01| FTINTRMWF F0, F2 +02081a01| FTINTRMWD F0, F2 +02241a01| FTINTRMVF F0, F2 +02281a01| FTINTRMVD F0, F2 +02441a01| FTINTRPWF F0, F2 +02481a01| FTINTRPWD F0, F2 +02641a01| FTINTRPVF F0, F2 +02681a01| FTINTRPVD F0, F2 +02841a01| FTINTRZWF F0, F2 +02881a01| FTINTRZWD F0, F2 +02a41a01| FTINTRZVF F0, F2 +02a81a01| FTINTRZVD F0, F2 +02c41a01| FTINTRNEWF F0, F2 +02c81a01| FTINTRNEWD F0, F2 +02e41a01| FTINTRNEVF F0, F2 +02e81a01| FTINTRNEVD F0, F2 +01101d01| FFINTFW F0, F1 +01181d01| FFINTFV F0, F1 +01201d01| FFINTDW F0, F1 +01281d01| FFINTDV F0, F1 +01041b01| FTINTWF F0, F1 +01081b01| FTINTWD F0, F1 +01241b01| FTINTVF F0, F1 +01281b01| FTINTVD F0, F1 +c7901208| FMADDF F5, F4, F6, F7 +c7902208| FMADDD F5, F4, F6, F7 +c7905208| FMSUBF F5, F4, F6, F7 +c7906208| FMSUBD F5, F4, F6, F7 +c7909208| FNMADDF F5, F4, F6, F7 +c790a208| FNMADDD F5, F4, F6, F7 +c790d208| FNMSUBF F5, F4, F6, F7 +c790e208| FNMSUBD F5, F4, F6, F7 +85806000| BSTRPICKW $0, R4, $0, R5 +85807f00| BSTRPICKW $31, R4, $0, R5 +85986f00| BSTRPICKW $15, R4, $6, R5 +8500c000| BSTRPICKV $0, R4, $0, R5 +8500ff00| BSTRPICKV $63, R4, $0, R5 +8518cf00| BSTRPICKV $15, R4, $6, R5 +85006000| BSTRINSW $0, R4, $0, R5 +85007f00| BSTRINSW $31, R4, $0, R5 +85186f00| BSTRINSW $15, R4, $6, R5 +85008000| BSTRINSV $0, R4, $0, R5 +8500bf00| BSTRINSV $63, R4, $0, R5 +85188f00| BSTRINSV $15, R4, $6, R5
diff --git a/loong64/loong64spec/spec.go b/loong64/loong64spec/spec.go new file mode 100644 index 0000000..4c32961 --- /dev/null +++ b/loong64/loong64spec/spec.go
@@ -0,0 +1,528 @@ +// 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. + +// loong64spec reads the "LoongArch-Vol1-EN.pdf" [1] to collect instruction +// encoding details and output to tables.go. +// +// usage: go run spec.go LoongArch-Vol1-EN.pdf +// +// [1]: https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.pdf + +package main + +import ( + "bytes" + "fmt" + "log" + "math" + "os" + "regexp" + "sort" + "strconv" + "strings" + + "rsc.io/pdf" +) + +func mergeMap(m1 map[string]string, m2 map[string]string) { + for k := range m2 { + m1[k] = m2[k] + } +} + +func main() { + log.SetFlags(0) + log.SetPrefix("loong64spec: ") + + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "usage: loong64spec LoongArch-Vol1-EN.pdf\n") + os.Exit(2) + } + f, err := pdf.Open(os.Args[1]) + if err != nil { + log.Fatal(err) + } + var prologue bytes.Buffer + prologue.Write([]byte("// Generated by loong64spec LoongArch-Vol1-EN.pdf, DO NOT EDIT.\n\n// Copyright 2024 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage loong64asm\n\n")) + + var op_f bytes.Buffer + op_f.Write([]byte("const (\n\t_ Op = iota\n")) + + var opstr_f bytes.Buffer + opstr_f.Write([]byte("var opstr = [...]string{\n")) + + var instFormats_f bytes.Buffer + instFormats_f.Write([]byte("var instFormats = [...]instFormat{\n")) + + // Scan document looking for instructions. + n := f.NumPage() + var ops []string + opstrs := map[string]string{} + instFormatComments := map[string]string{} + instFormats := map[string]string{} + var fp int + for pageNum := 1; pageNum <= n; pageNum++ { + p := f.Page(pageNum) + if fp == 0 { + if !isFirstPage(p) { + continue + } + fp = pageNum + } + cPageOps, cPageOpstrs, cPageInstFormatComments, cPageInstFormats := parsePage(pageNum, p, fp == pageNum) + ops = append(ops, cPageOps...) + mergeMap(opstrs, cPageOpstrs) + mergeMap(instFormatComments, cPageInstFormatComments) + mergeMap(instFormats, cPageInstFormats) + } + + sort.Strings(ops) + + for _, op := range ops { + // 1. write op + op_f.Write([]byte(fmt.Sprintf("\t%s\n", op))) + // 2. write opstr + opstr_f.Write([]byte(fmt.Sprintf("\t%s\n", opstrs[op]))) + // 3. write instFormat + instFormats_f.Write([]byte(fmt.Sprintf("\t%s\n\t%s\n", instFormatComments[op], instFormats[op]))) + } + + op_f.Write([]byte(")\n\n")) + opstr_f.Write([]byte("}\n\n")) + instFormats_f.Write([]byte("}\n")) + + fileTables, err := os.Create("tables.go") + defer fileTables.Close() + + fileTables.Write(prologue.Bytes()) + fileTables.Write(op_f.Bytes()) + fileTables.Write(opstr_f.Bytes()) + fileTables.Write(instFormats_f.Bytes()) + + fileTables.Close() +} + +func isFirstPage(page pdf.Page) bool { + content := page.Content() + appendixb := "AppendixB" + ct := "" + for _, t := range content.Text { + ct += t.S + if ct == "AppendixB" { + return true + } + if strings.HasPrefix(appendixb, ct) { + continue + } else { + return false + } + } + return false +} + +func getArg(name string) (length int, argName string) { + switch { + case strings.Contains("arg_fd", name): + return 5, "arg_fd" + case strings.Contains("arg_fj", name): + return 5, "arg_fj" + case strings.Contains("arg_fk", name): + return 5, "arg_fk" + case strings.Contains("arg_fa", name): + return 5, "arg_fa" + case strings.Contains("arg_rd", name): + return 5, "arg_rd" + case strings.Contains("arg_rj", name) || name == "rj!=0,1": + return 5, "arg_rj" + case strings.Contains("arg_rk", name): + return 5, "arg_rk" + case name == "csr": + return 14, "arg_csr_23_10" + case strings.Contains("arg_cd", name): + return 5, "arg_cd" + case strings.Contains("arg_cj", name): + return 5, "arg_cj" + case strings.Contains("arg_ca", name): + return 5, "arg_ca" + case strings.Contains(name, "sa"): + length, _ := strconv.Atoi(strings.Split(name, "sa")[1]) + if length == 2 { + argName = "arg_sa2_16_15" + } else { + argName = "arg_sa3_17_15" + } + return length, argName + case strings.Contains("arg_seq_17_10", name): + return 8, "arg_seq_17_10" + case strings.Contains("arg_op_4_0", name): + return 5, "arg_op_4_0" + case strings.Contains(name, "ui"): + length, _ := strconv.Atoi(strings.Split(name, "ui")[1]) + if length == 5 { + argName = "arg_ui5_14_10" + } else if length == 6 { + argName = "arg_ui6_15_10" + } else { + argName = "arg_ui12_21_10" + } + return length, argName + case strings.Contains("arg_lsbw", name): + return 5, "arg_lsbw" + case strings.Contains("arg_msbw", name): + return 5, "arg_msbw" + case strings.Contains("arg_lsbd", name): + return 6, "arg_lsbd" + case strings.Contains("arg_msbd", name): + return 6, "arg_msbd" + case strings.Contains(name, "si"): + length, _ := strconv.Atoi(strings.Split(name, "si")[1]) + if length == 12 { + argName = "arg_si12_21_10" + } else if length == 14 { + argName = "arg_si14_23_10" + } else if length == 16 { + argName = "arg_si16_25_10" + } else { + argName = "arg_si20_24_5" + } + return length, argName + case strings.Contains(name, "offs"): + splitName := strings.Split(name, ":") + left, _ := strconv.Atoi(strings.Split(splitName[0], "[")[1]) + right, _ := strconv.Atoi(strings.Split(splitName[1], "]")[0]) + return left - right + 1, "offs" + default: + return 0, "" + } +} + +func binstrToHex(str string) string { + rst := 0 + hex := "0x" + charArray := []byte(str) + for i := 0; i < 32; { + rst = 1*(int(charArray[i+3])-48) + 2*(int(charArray[i+2])-48) + 4*(int(charArray[i+1])-48) + 8*(int(charArray[i])-48) + switch rst { + case 10: + hex = hex + "a" + case 11: + hex = hex + "b" + case 12: + hex = hex + "c" + case 13: + hex = hex + "d" + case 14: + hex = hex + "e" + case 15: + hex = hex + "f" + default: + hex += strconv.Itoa(rst) + } + + i = i + 4 + } + return hex +} + +/* +Here we deal with the instruction FCMP.cond.S/D, which has the following format: + + | 31 - 20 | 19 - 15 | 14 - 10 | 9 - 5 | 4 | 3 | 2 - 0 | + |---------|---------|---------|-------|---|---|-------| + | op | cond | fk | fj | 0 | 0 | cd | + +The `cond` field has these possible values: + + "CAF": "00", + "CUN": "08", + "CEQ": "04", + "CUEQ": "0c", + "CLT": "02", + "CULT": "0a", + "CLE": "06", + "CULE": "0e", + "CNE": "10", + "COR": "14", + "CUNE": "18", + "SAF": "01", + "SUN": "09", + "SEQ": "05", + "SUEQ": "0d", + "SLT": "03", + "SULT": "0b", + "SLE": "07", + "SULE": "0f", + "SNE": "11", + "SOR": "15", + "SUNE": "19", + +These values are the hexadecimal numbers of bits 19 to 15, the same as +described in the instruction set manual. + +The following code defines a map, the values in it represent the hexadecimal +encoding of the cond field in the entire instruction. In this case, the upper +4 bits and the lowest 1 bit are encoded separately, so the encoding is +different from the encoding described above. +*/ +func dealWithFcmp(ds string) (fcmpConditions map[string]map[string]string) { + conds := map[string]string{ + "CAF": "00", + "CUN": "40", + "CEQ": "20", + "CUEQ": "60", + "CLT": "10", + "CULT": "50", + "CLE": "30", + "CULE": "70", + "CNE": "80", + "COR": "a0", + "CUNE": "c0", + "SAF": "08", + "SUN": "48", + "SEQ": "28", + "SUEQ": "68", + "SLT": "18", + "SULT": "58", + "SLE": "38", + "SULE": "78", + "SNE": "88", + "SOR": "a8", + "SUNE": "c8", + } + fcmpConditions = make(map[string]map[string]string) + for k, v := range conds { + op := fmt.Sprintf("FCMP_%s_%s", k, ds) + opstr := fmt.Sprintf("FCMP_%s_%s:\t\"FCMP.%s.%s\",", k, ds, k, ds) + instFormatComment := fmt.Sprintf("// FCMP.%s.%s cd, fj, fk", k, ds) + var instFormat string + if ds == "D" { + instFormat = fmt.Sprintf("{mask: 0xffff8018, value: 0x0c2%s000, op: FCMP_%s_%s, args: instArgs{arg_cd, arg_fj, arg_fk}},", v, k, ds) + } else { + instFormat = fmt.Sprintf("{mask: 0xffff8018, value: 0x0c1%s000, op: FCMP_%s_%s, args: instArgs{arg_cd, arg_fj, arg_fk}},", v, k, ds) + } + + fcmpConditions[op] = make(map[string]string) + fcmpConditions[op]["op"] = op + fcmpConditions[op]["opstr"] = opstr + fcmpConditions[op]["instFormatComment"] = instFormatComment + fcmpConditions[op]["instFormat"] = instFormat + } + return +} + +func findWords(chars []pdf.Text) (words []pdf.Text) { + for i := 0; i < len(chars); { + xRange := []float64{chars[i].X, chars[i].X} + j := i + 1 + + // Find all chars on one line. + for j < len(chars) && chars[j].Y == chars[i].Y { + xRange[1] = chars[j].X + j++ + } + + // we need to note that the word may change line(Y) but belong to one cell. So, after loop over all continued + // chars whose Y are same, check if the next char's X belong to the range of xRange, if true, means it should + // be contact to current word, because the next word's X should bigger than current one. + for j < len(chars) && chars[j].X >= xRange[0] && chars[j].X <= xRange[1] { + j++ + } + + var end float64 + // Split line into words (really, phrases). + for k := i; k < j; { + ck := &chars[k] + s := ck.S + end = ck.X + ck.W + charSpace := ck.FontSize / 6 + wordSpace := ck.FontSize * 2 / 3 + l := k + 1 + for l < j { + // Grow word. + cl := &chars[l] + + if math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+charSpace { + s += cl.S + end = cl.X + cl.W + l++ + continue + } + // Add space to phrase before next word. + if math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+wordSpace { + s += " " + cl.S + end = cl.X + cl.W + l++ + continue + } + break + } + f := ck.Font + words = append(words, pdf.Text{f, ck.FontSize, ck.X, ck.Y, end - ck.X, s}) + k = l + } + i = j + } + + return words +} + +func parsePage(num int, p pdf.Page, isFP bool) (ops []string, opstrs map[string]string, instFormatComments map[string]string, instFormats map[string]string) { + opstrs = make(map[string]string) + instFormatComments = make(map[string]string) + instFormats = make(map[string]string) + + content := p.Content() + + var text []pdf.Text + for _, t := range content.Text { + text = append(text, t) + } + + // table name(70), table header(64), page num(3) + if isFP { + text = text[134 : len(text)-3] + } else { + text = text[64 : len(text)-3] + } + + text = findWords(text) + + for i := 0; i < len(text); { + var fcmpConditions map[string]map[string]string + if strings.HasPrefix(text[i].S, "FCMP") { + fcmpConditions = dealWithFcmp(strings.Split(text[i].S, ".")[2]) + + for fc, inst := range fcmpConditions { + ops = append(ops, inst["op"]) + opstrs[fc] = inst["opstr"] + instFormatComments[fc] = inst["instFormatComment"] + instFormats[fc] = inst["instFormat"] + } + t := i + 1 + for ; text[t].Y == text[i].Y; t++ { + continue + } + i = t + continue + } + + op := strings.Replace(text[i].S, ".", "_", -1) + opstr := fmt.Sprintf("%s:\t\"%s\",", op, text[i].S) + instFormatComment := "" + binValue := "" + binMask := "" + instArgs := "" + offs := false + var offArgs []string + + j := i + 1 + for ; j < len(text) && text[j].Y == text[i].Y; j++ { + + // Some instruction has no arguments, so the next word(text[j].S) is not the arguments string but 0/1 bit, it shouldn't be skipped. + if res, _ := regexp.MatchString("^\\d+$", text[j].S); j == i+1 && res == false { + instFormatComment = fmt.Sprintf("// %s %s", text[i].S, strings.Replace(text[j].S, ",", ", ", -1)) + continue + } + if text[j].S == "0" || text[j].S == "1" { + binValue += text[j].S + binMask += "1" + } else { + argLen, argName := getArg(text[j].S) + + // Get argument's length failed, compute it by other arguments. + if argLen == 0 { + left := 31 - len(binValue) + right := 0 + l := j + 1 + if l < len(text) && text[l].Y == text[j].Y { + for ; text[l].Y == text[j].Y; l++ { + if text[l].S == "0" || text[l].S == "1" { + right += 1 + } else { + tArgLen, _ := getArg(text[l].S) + if tArgLen == 0 { + fmt.Fprintf(os.Stderr, "there are more than two args whose length is unknown.\n") + } + right += tArgLen + } + } + } + argLen = left - right + 1 + argName = "arg_" + text[j].S + "_" + strconv.FormatInt(int64(left), 10) + "_" + strconv.FormatInt(int64(right), 10) + } + + for k := 0; k < argLen; k++ { + binValue += "0" + binMask += "0" + } + + if argName != "offs" { + if instArgs != "" { + instArgs = ", " + instArgs + } + instArgs = argName + instArgs + } else { + offs = true + offArgs = append(offArgs, text[j].S) + } + } + } + + // The real offset is a combination of two offsets in the binary code of the instruction, for example: BEQZ + if offs && offArgs != nil { + var left int + var right int + if len(offArgs) == 1 { + left, _ = strconv.Atoi(strings.Split(strings.Split(offArgs[0], ":")[0], "[")[1]) + right, _ = strconv.Atoi(strings.Split(strings.Split(offArgs[0], ":")[1], "]")[0]) + } else if len(offArgs) == 2 { + left, _ = strconv.Atoi(strings.Split(strings.Split(offArgs[1], ":")[0], "[")[1]) + right, _ = strconv.Atoi(strings.Split(strings.Split(offArgs[0], ":")[1], "]")[0]) + } + + if instArgs == "" { + instArgs = fmt.Sprintf("arg_offset_%d_%d", left, right) + } else { + instArgs += fmt.Sprintf(", arg_offset_%d_%d", left, right) + } + } + + ops = append(ops, op) + opstrs[op] = opstr + if instFormatComment == "" { + instFormatComment = "// " + text[i].S + } else if strings.HasPrefix(op, "AM") { + instFormatComment = fmt.Sprintf("// %s rd, rk, rj", text[i].S) + } + instFormatComments[op] = instFormatComment + // The parameter order of some instructions is inconsistent in encoding and syntax, such as BSTRINS.* + if instArgs != "" { + args := strings.Split(instFormatComment, " ")[2:] + tInstArgs := strings.Split(instArgs, ", ") + newOrderedInstArgs := []string{} + for _, a := range args { + a = strings.Split(a, ",")[0] + for _, aa := range tInstArgs { + if strings.Contains(aa, a) { + newOrderedInstArgs = append(newOrderedInstArgs, aa) + break + } else if a == "rd" && aa == "arg_fd" { + newOrderedInstArgs = append(newOrderedInstArgs, "arg_rd") + break + } + } + } + instArgs = strings.Join(newOrderedInstArgs, ", ") + } + if strings.HasPrefix(op, "AM") { + instArgs = "arg_rd, arg_rk, arg_rj" + } + instFormat := fmt.Sprintf("{mask: %s, value: %s, op: %s, args: instArgs{%s}},", binstrToHex(binMask), binstrToHex(binValue), op, instArgs) + instFormats[op] = instFormat + + i = j // next instruction + } + + return +}