s390x: add s390x disassembler support for the plan9
Change-Id: I0eb9a10535175bb70dbab5737c4e02e68fd44c94
Reviewed-on: https://go-review.googlesource.com/c/arch/+/620475
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Vishwanatha HD <vishwanatha.hd@ibm.com>
diff --git a/s390x/s390xasm/decode_test.go b/s390x/s390xasm/decode_test.go
index 5ca0b74..29bce8e 100644
--- a/s390x/s390xasm/decode_test.go
+++ b/s390x/s390xasm/decode_test.go
@@ -75,6 +75,8 @@
switch syntax {
case "gnu":
out = GNUSyntax(inst, pc)
+ case "plan9":
+ out = GoSyntax(inst, pc, nil)
default:
t.Errorf("unknown syntax %q", syntax)
continue
diff --git a/s390x/s390xasm/plan9.go b/s390x/s390xasm/plan9.go
new file mode 100644
index 0000000..b4df0b8
--- /dev/null
+++ b/s390x/s390xasm/plan9.go
@@ -0,0 +1,1282 @@
+// 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 s390xasm
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+var vectorSize = map[int]string{0: "B", 1: "H", 2: "F", 3: "G", 4: "Q"}
+var vectorCS = map[int]string{0: "BS", 1: "HS", 2: "FS", 3: "GS"}
+
+// GoSyntax returns the Go assembler syntax for the instruction.
+// The syntax was originally defined by Plan 9.
+// The inst relates to single instruction.
+// 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 }
+ }
+
+ var args []string
+ opString := inst.Op.String()
+ op := strings.ToUpper(opString)
+ for i := 0; i < len(inst.Args); i++ {
+ if inst.Args[i] == nil {
+ break
+ }
+ switch inst.Args[i].(type) {
+ case Disp12, Disp20:
+ var temp []string
+ switch inst.Args[i+1].(type) {
+ case Index: // D(X,B)
+ for j := 0; j < 3; j++ {
+ temp = append(temp, plan9Arg(&inst, pc, symname, inst.Args[i+j]))
+ }
+ args = append(args, mem_operandx(temp))
+ i = i + 2
+ case Base: // D(B)
+ for j := 0; j < 2; j++ {
+ temp = append(temp, plan9Arg(&inst, pc, symname, inst.Args[i+j]))
+ }
+ args = append(args, mem_operand(temp))
+ i = i + 1
+ case VReg: // D(B)
+ for j := 0; j < 3; j++ {
+ temp = append(temp, plan9Arg(&inst, pc, symname, inst.Args[i+j]))
+ }
+ args = append(args, mem_operandv(temp))
+ i = i + 2
+ case Len: // D(L,B)
+ for j := 0; j < 3; j++ {
+ temp = append(temp, plan9Arg(&inst, pc, symname, inst.Args[i+j]))
+ }
+ ar1, ar2 := mem_operandl(temp)
+ args = append(args, ar1, ar2)
+ i = i + 2
+ default: // D(R,B)
+ for j := 0; j < 3; j++ {
+ temp = append(temp, plan9Arg(&inst, pc, symname, inst.Args[i+j]))
+ }
+ args = append(args, mem_operandx(temp))
+ i = i + 2
+ }
+ default:
+ args = append(args, plan9Arg(&inst, pc, symname, inst.Args[i]))
+ }
+ }
+ if strings.HasPrefix(op, "V") || strings.Contains(op, "WFC") || strings.Contains(op, "WFK") {
+ args = args[:len(args)-1]
+ }
+
+ switch inst.Op {
+ default:
+ switch len(args) {
+ case 0:
+ return op
+ case 1:
+ return fmt.Sprintf("%s %s", op, args[0])
+ case 2:
+ if reverseOperandOrder(inst.Op) {
+ args[0], args[1] = args[1], args[0]
+ }
+ case 3:
+ if reverseOperandOrder(inst.Op) {
+ args[0], args[2] = args[2], args[0]
+ } else if reverseAllOperands(inst.Op) {
+ args[0], args[1], args[2] = args[1], args[2], args[0]
+ }
+ case 4:
+ if reverseOperandOrder(inst.Op) {
+ args[0], args[3] = args[3], args[0]
+ } else if reverseAllOperands(inst.Op) {
+ args[0], args[1], args[2], args[3] = args[1], args[2], args[3], args[0]
+ }
+ }
+ case LCGR, LCGFR:
+ switch inst.Op {
+ case LCGR:
+ op = "NEG"
+ case LCGFR:
+ op = "NEGW"
+ }
+ if args[0] == args[1] {
+ args = args[:1]
+ } else {
+ args[0], args[1] = args[1], args[0]
+ }
+ case LD, LE, LG, LGF, LLGF, LGH, LLGH, LGB, LLGC, LDY, LEY, LRVG, LRV, LRVH:
+ args[0], args[1] = args[1], args[0]
+ switch inst.Op {
+ case LG:
+ op = "MOVD"
+ case LGF:
+ op = "MOVW"
+ case LLGF:
+ op = "MOVWZ"
+ case LGH:
+ op = "MOVH"
+ case LLGH:
+ op = "MOVHZ"
+ case LGB:
+ op = "MOVB"
+ case LLGC:
+ op = "MOVBZ"
+ case LDY, LD:
+ op = "FMOVD"
+ case LEY, LE:
+ op = "FMOVS"
+ case LRVG:
+ op = "MOVDBR"
+ case LRV:
+ op = "MOVWBR"
+ case LRVH:
+ op = "MOVHBR"
+ }
+ case LA, LAY:
+ args[0], args[1] = args[1], args[0]
+ op = "MOVD"
+
+ case LAA, LAAG, LAAL, LAALG, LAN, LANG, LAX, LAXG, LAO, LAOG:
+ args[0], args[1] = args[1], args[0]
+ case LM, LMY, LMG: // Load Multiple
+ switch inst.Op {
+ case LM, LMY:
+ op = "LMY"
+ }
+ args[0], args[1], args[2] = args[2], args[0], args[1]
+
+ case STM, STMY, STMG: // Store Multiple
+ switch inst.Op {
+ case STM, STMY:
+ op = "STMY"
+ }
+ case ST, STY, STG, STHY, STCY, STRVG, STRV:
+ switch inst.Op {
+ case ST, STY:
+ op = "MOVW"
+ case STHY:
+ op = "MOVH"
+ case STCY:
+ op = "MOVB"
+ case STG:
+ op = "MOVD"
+ case STRVG:
+ op = "MOVDBR"
+ case STRV:
+ op = "MOVWBR"
+ }
+ case LGR, LGFR, LGHR, LGBR, LLGFR, LLGHR, LLGCR, LRVGR, LRVR, LDR:
+ switch inst.Op {
+ case LGR:
+ op = "MOVD"
+ case LGFR:
+ op = "MOVW"
+ case LGHR:
+ op = "MOVH"
+ case LGBR:
+ op = "MOVB"
+ case LLGFR:
+ op = "MOVWZ"
+ case LLGHR:
+ op = "MOVHZ"
+ case LLGCR:
+ op = "MOVBZ"
+ case LRVGR:
+ op = "MOVDBR"
+ case LRVR:
+ op = "MOVWBR"
+ case LDR:
+ op = "FMOVD"
+ }
+ args[0], args[1] = args[1], args[0]
+ case LZDR:
+ op = "FMOVD"
+ return op + " " + "$0" + ", " + args[0]
+ case LZER:
+ op = "FMOVS"
+ return op + " " + "$0" + ", " + args[0]
+ case STD, STDY, STE, STEY:
+ switch inst.Op {
+ case STD, STDY:
+ op = "FMOVD"
+ case STE, STEY:
+ op = "FMOVS"
+ }
+
+ case LGHI, LLILH, LLIHL, LLIHH, LGFI, LLILF, LLIHF:
+ switch inst.Op {
+ case LGFI:
+ op = "MOVW"
+ case LGHI:
+ num, err := strconv.ParseInt(args[1][1:], 10, 16)
+ if err != nil {
+ return fmt.Sprintf("plan9Arg: error in converting ParseInt:%s", err)
+ }
+ if num == int64(int8(num)) {
+ op = "MOVB"
+ } else {
+ op = "MOVH"
+ }
+ default:
+ op = "MOVD"
+ }
+ args[0], args[1] = args[1], args[0]
+ case ARK, AGRK, ALGRK:
+ switch inst.Op {
+ case ARK:
+ op = "ADDW"
+ case AGRK:
+ op = "ADD"
+ case ALGRK:
+ op = "ADDC"
+ }
+ if args[0] == args[1] {
+ args[0], args[1] = args[2], args[0]
+ args = args[:2]
+ } else {
+ args[0], args[1], args[2] = args[2], args[1], args[0]
+ }
+ case AGHIK, AHIK, ALGHSIK:
+ num, err := strconv.ParseInt(args[2][1:], 10, 32)
+ if err != nil {
+ return fmt.Sprintf("plan9Arg: error in converting ParseInt:%s", err)
+ }
+ switch inst.Op {
+ case AGHIK:
+ if num < 0 {
+ op = "SUB"
+ args[2] = args[2][:1] + args[2][2:]
+ } else {
+ op = "ADD"
+ }
+ case AHIK:
+ op = "ADDW"
+ case ALGHSIK:
+ if num < 0 {
+ op = "SUBC"
+ args[2] = args[2][:1] + args[2][2:]
+ } else {
+ op = "ADDC"
+ }
+ }
+ args[0], args[1], args[2] = args[2], args[1], args[0]
+ case AGHI, AHI, AGFI, AFI, AR, ALCGR:
+ num, err := strconv.ParseInt(args[1][1:], 10, 32)
+ if err != nil {
+ return fmt.Sprintf("plan9Arg: error in converting ParseInt:%s", err)
+ }
+ switch inst.Op {
+ case AGHI, AGFI:
+ if num < 0 {
+ op = "SUB"
+ args[1] = args[1][:1] + args[1][2:]
+ } else {
+ op = "ADD"
+ }
+ case AHI, AFI, AR:
+ op = "ADDW"
+ case ALCGR:
+ op = "ADDE"
+ }
+ args[0], args[1] = args[1], args[0]
+ case AEBR, ADBR, DDBR, DEBR, MDBR, MEEBR, SDBR, SEBR, LPDBR, LNDBR, LPDFR, LNDFR, LCDFR, LCEBR, LEDBR, LDEBR, SQDBR, SQEBR:
+ switch inst.Op {
+ case AEBR:
+ op = "FADDS"
+ case ADBR:
+ op = "FADD"
+ case DDBR:
+ op = "FDIV"
+ case DEBR:
+ op = "FDIVS"
+ case MDBR:
+ op = "FMUL"
+ case MEEBR:
+ op = "FMULS"
+ case SDBR:
+ op = "FSUB"
+ case SEBR:
+ op = "FSUBS"
+ case LPDBR:
+ op = "FABS"
+ case LNDBR:
+ op = "FNABS"
+ case LCDFR:
+ op = "FNEG"
+ case LCEBR:
+ op = "FNEGS"
+ case SQDBR:
+ op = "FSQRT"
+ case SQEBR:
+ op = "FSQRTS"
+ }
+ args[0], args[1] = args[1], args[0]
+ case SR, SGR, SLGR, SLFI:
+ switch inst.Op {
+ case SR, SLFI:
+ op = "SUBW"
+ case SGR:
+ op = "SUB"
+ case SLGR:
+ op = "SUBC"
+ }
+ args[0], args[1] = args[1], args[0]
+ case SGRK, SLGRK, SRK:
+ switch inst.Op {
+ case SGRK:
+ op = "SUB"
+ case SLGRK:
+ op = "SUBC"
+ case SRK:
+ op = "SUBW"
+ }
+ if args[0] == args[1] {
+ args[0], args[1] = args[2], args[0]
+ args = args[:2]
+ } else {
+ args[0], args[1], args[2] = args[2], args[1], args[0]
+ }
+ case SLBGR:
+ op = "SUBE"
+ args[0], args[1] = args[1], args[0]
+ case MSGFR, MHI, MSFI, MSGFI:
+ switch inst.Op {
+ case MSGFR, MHI, MSFI:
+ op = "MULLW"
+ case MSGFI:
+ op = "MULLD"
+ }
+ args[0], args[1] = args[1], args[0]
+
+ case NGR, NR, NILL, NILF, NILH, OGR, OR, OILL, OILF, OILH, XGR, XR, XILF:
+ op = bitwise_op(inst.Op)
+ args[0], args[1] = args[1], args[0]
+ switch inst.Op {
+ case NILL:
+ if int(inst.Args[1].(Sign16)) < 0 {
+ op = "ANDW"
+ }
+
+ case NILF:
+ if int(inst.Args[1].(Sign32)) < 0 {
+ op = "AND"
+ }
+ case OILF:
+ if int(inst.Args[1].(Sign32)) < 0 {
+ op = "ORW"
+ }
+ case XILF:
+ if int(inst.Args[1].(Sign32)) < 0 {
+ op = "XORW"
+ }
+ }
+
+ case NGRK, NRK, OGRK, ORK, XGRK, XRK: // opcode R1, R2, R3
+ op = bitwise_op(inst.Op)
+ args[0], args[1], args[2] = args[1], args[2], args[0]
+ case SLLG, SRLG, SLLK, SRLK, RLL, RLLG, SRAK, SRAG:
+ switch inst.Op {
+ case SLLG:
+ op = "SLD"
+ case SRLG:
+ op = "SRD"
+ case SLLK:
+ op = "SLW"
+ case SRLK:
+ op = "SRW"
+ case SRAK:
+ op = "SRAW"
+ case SRAG:
+ op = "SRAD"
+ }
+ args[0], args[1], args[2] = args[2], args[1], args[0]
+ case TRAP2, SVC:
+ op = "SYSALL"
+ case CR, CLR, CGR, CLGR, KDBR, CDBR, CEBR, CGHI, CHI, CGFI, CLGFI, CFI, CLFI:
+ switch inst.Op {
+ case CGHI, CGFI, CGR:
+ op = "CMP"
+ case CHI, CFI, CR:
+ op = "CMPW"
+ case CLGFI, CLGR:
+ op = "CMPU"
+ case CLFI, CLR:
+ op = "CMPWU"
+ case CDBR:
+ op = "FCMPU"
+ case KDBR:
+ op = "FCMPO"
+ }
+ case CEFBRA, CDFBRA, CEGBRA, CDGBRA, CELFBR, CDLFBR, CELGBR, CDLGBR, CFEBRA, CFDBRA, CGEBRA, CGDBRA, CLFEBR, CLFDBR, CLGEBR, CLGDBR:
+ args[0], args[1] = args[2], args[0]
+ args = args[:2]
+ case CGRJ, CGIJ:
+ mask, err := strconv.Atoi(args[2][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ var check bool
+ switch mask & 0xf {
+ case 2:
+ op = "CMPBGT"
+ check = true
+ case 4:
+ op = "CMPBLT"
+ check = true
+ case 6:
+ op = "CMPBNE"
+ check = true
+ case 8:
+ op = "CMPBEQ"
+ check = true
+ case 10:
+ op = "CMPBGE"
+ check = true
+ case 12:
+ op = "CMPBLE"
+ check = true
+ }
+ if check {
+ args[2] = args[3]
+ args = args[:3]
+ }
+ case CLGRJ, CLGIJ:
+ mask, err := strconv.Atoi(args[2][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ var check bool
+ switch mask & 0xf {
+ case 2:
+ op = "CMPUBGT"
+ check = true
+ case 4:
+ op = "CMPUBLT"
+ check = true
+ case 7:
+ op = "CMPUBNE"
+ check = true
+ case 8:
+ op = "CMPUBEQ"
+ check = true
+ case 10:
+ op = "CMPUBGE"
+ check = true
+ case 12:
+ op = "CMPUBLE"
+ check = true
+ }
+ if check {
+ args[2] = args[3]
+ args = args[:3]
+ }
+ case CLRJ, CRJ, CIJ, CLIJ:
+ args[0], args[1], args[2], args[3] = args[2], args[0], args[1], args[3]
+ case BRC, BRCL:
+ mask, err := strconv.Atoi(args[0][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ opStr, check := branch_relative_op(mask, inst.Op)
+ if opStr != "" {
+ op = opStr
+ }
+ if check {
+ args[0] = args[1]
+ args = args[:1]
+ }
+ case BCR:
+ mask, err := strconv.Atoi(args[0][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ opStr, check := branchOnConditionOp(mask, inst.Op)
+ if opStr != "" {
+ op = opStr
+ }
+ if op == "SYNC" || op == "NOPH" {
+ return op
+ }
+ if check {
+ args[0] = args[1]
+ args = args[:1]
+ }
+ case LOCGR:
+ mask, err := strconv.Atoi(args[2][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ var check bool
+ switch mask & 0xf {
+ case 2: //Greaterthan (M=2)
+ op = "MOVDGT"
+ check = true
+ case 4: //Lessthan (M=4)
+ op = "MOVDLT"
+ check = true
+ case 7: // Not Equal (M=7)
+ op = "MOVDNE"
+ check = true
+ case 8: // Equal (M=8)
+ op = "MOVDEQ"
+ check = true
+ case 10: // Greaterthan or Equal (M=10)
+ op = "MOVDGE"
+ check = true
+ case 12: // Lessthan or Equal (M=12)
+ op = "MOVDLE"
+ check = true
+ }
+ if check {
+ args[0], args[1] = args[1], args[0]
+ args = args[:2]
+ } else {
+ args[0], args[1], args[2] = args[2], args[1], args[0]
+ }
+ case BRASL:
+ op = "CALL" // BL
+ args[0] = args[1]
+ args = args[:1]
+ case X, XY, XG:
+ switch inst.Op {
+ case X, XY:
+ op = "XORW"
+ case XG:
+ op = "XOR"
+ }
+ case N, NY, NG, O, OY, OG, XC, NC, OC, MVC, MVCIN, CLC:
+ switch inst.Op {
+ case N, NY:
+ op = "ANDW"
+ case NG:
+ op = "AND"
+ case O, OY:
+ op = "ORW"
+ case OG:
+ op = "OR"
+ }
+ args[0], args[1] = args[1], args[0]
+ case S, SY, SLBG, SLG, SG:
+ switch inst.Op {
+ case S, SY:
+ op = "SUBW"
+ case SLBG:
+ op = "SUBE"
+ case SLG:
+ op = "SUBC"
+ case SG:
+ op = "SUB"
+ }
+ args[0], args[1] = args[1], args[0]
+ case MSG, MSY, MS:
+ switch inst.Op {
+ case MSG:
+ op = "MULLD"
+ case MSY, MS:
+ op = "MULLW"
+ }
+ case A, AY, ALCG, ALG, AG:
+ switch inst.Op {
+ case A, AY:
+ op = "ADDW"
+ case ALCG:
+ op = "ADDE"
+ case ALG:
+ op = "ADDC"
+ case AG:
+ op = "ADD"
+ }
+ args[0], args[1] = args[1], args[0]
+ case RISBG, RISBGN, RISBHG, RISBLG, RNSBG, RXSBG, ROSBG:
+ switch inst.Op {
+ case RNSBG, RXSBG, ROSBG:
+ num, err := strconv.Atoi(args[2][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ if ((num >> 7) & 0x1) != 0 {
+ op = op + "T"
+ }
+ case RISBG, RISBGN, RISBHG, RISBLG:
+ num, err := strconv.Atoi(args[3][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ if ((num >> 7) & 0x1) != 0 {
+ op = op + "Z"
+ }
+ }
+ if len(args) == 5 {
+ args[0], args[1], args[2], args[3], args[4] = args[2], args[3], args[4], args[1], args[0]
+ } else {
+ args[0], args[1], args[2], args[3] = args[2], args[3], args[1], args[0]
+ }
+
+ case VEC, VECL, VCLZ, VCTZ, VREPI, VPOPCT: //mnemonic V1, V2, M3
+ mask, err := strconv.Atoi(args[2][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi for %q:%s", op, err)
+ }
+ val := mask & 0x7
+ if val >= 0 && val < 4 {
+ op = op + vectorSize[val]
+ args = args[:2]
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask value: %v \n", op, mask)
+ }
+ switch inst.Op {
+ case VCLZ, VCTZ, VREPI, VPOPCT:
+ args[0], args[1] = args[1], args[0]
+ default:
+ }
+ //Mnemonic V1, V2, V3, M4 or Mnemonic V1, I2, I3, M4 or Mnemonic V1, V3, I2, M4
+ case VA, VS, VACC, VAVG, VAVGL, VMX, VMXL, VMN, VMNL, VGFM, VGM, VREP, VERLLV, VESLV, VSCBI, VSUM, VSUMG, VSUMQ, VMH, VMLH, VML, VME, VMLE, VMO, VMLO:
+ mask, err := strconv.Atoi(args[3][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ val := mask & 0x7
+ switch inst.Op {
+ case VA, VS, VACC, VSCBI:
+ if val >= 0 && val < 5 {
+ if args[0] == args[2] {
+ args[0], args[1] = args[1], args[0]
+ args = args[:2]
+ } else if inst.Op == VS {
+ if args[0] == args[1] {
+ args[0] = args[2]
+ args = args[:2]
+ } else {
+ args[0], args[2] = args[2], args[0]
+ args = args[:3]
+ }
+ } else {
+ args[0], args[1], args[2] = args[1], args[2], args[0]
+ args = args[:3]
+ }
+ op = op + vectorSize[val]
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask value: %v \n", op, mask)
+ }
+ case VAVG, VAVGL, VMX, VMXL, VMN, VMNL, VGFM, VGM:
+ if val >= 0 && val < 4 {
+ op = op + vectorSize[val]
+ args[0], args[1], args[2] = args[1], args[2], args[0]
+ args = args[:3]
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask value: %v \n", op, mask)
+ }
+ case VREP, VERLLV, VESLV:
+ if val >= 0 && val < 4 {
+ op = op + vectorSize[val]
+ args[0], args[1], args[2] = args[2], args[1], args[0]
+ args = args[:3]
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask value: %v \n", op, mask)
+ }
+ case VSUM, VSUMG, VSUMQ:
+ var off int
+ switch inst.Op {
+ case VSUM:
+ off = 0
+ case VSUMG:
+ off = 1
+ case VSUMQ:
+ off = 2
+ }
+ if (val > (-1 + off)) && (val < (2 + off)) {
+ op = op + vectorSize[val]
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask value: %v \n", op, mask)
+ }
+ args = args[:3]
+ case VML, VMH, VMLH, VME, VMLE, VMO, VMLO:
+ if val >= 0 && val < 3 {
+ op = op + vectorSize[val]
+ }
+ if op == "VML" && val == 2 {
+ op = op + "W"
+ }
+ if args[0] == args[2] {
+ args[0], args[1] = args[1], args[0]
+ args = args[:2]
+ } else {
+ args[0], args[1], args[2] = args[1], args[2], args[0]
+ args = args[:3]
+ }
+ }
+
+ case VGFMA, VERIM, VMAH, VMALH: // Mnemonic V1, V2, V3, V4/I4, M5
+ mask, err := strconv.Atoi(args[4][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ val := mask & 0x7
+ args = args[:4]
+ var off int
+ switch inst.Op {
+ case VMAH, VMALH:
+ off = -1
+ }
+
+ if val >= 0 && val < (4+off) {
+ op = op + vectorSize[val]
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask value: %v \n", op, mask)
+ }
+ switch inst.Op {
+ case VGFMA, VMAH, VMALH:
+ args[0], args[1], args[2], args[3] = args[1], args[2], args[3], args[0]
+ default:
+ args[0], args[3] = args[3], args[0]
+ }
+ case VSTRC, VFAE, VFEE, VFENE:
+ var off uint8
+ switch inst.Op {
+ case VSTRC:
+ off = uint8(1)
+ default:
+ off = uint8(0)
+ }
+ m1, err := strconv.Atoi(args[3+off][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ m2, err := strconv.Atoi(args[4+off][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ index := m1 & 0x3
+ if index < 0 || index > 2 {
+ return fmt.Sprintf("specification exception is recognized for %q with mask values: %v, %v \n", op, m1, m2)
+ }
+ switch m2 {
+ case 0:
+ op = op + vectorSize[index]
+ case 1:
+ op = op + vectorCS[index]
+ case 2:
+ op = op + "Z" + vectorSize[index]
+ case 3:
+ op = op + "Z" + vectorCS[index]
+ default:
+ return fmt.Sprintf("specification exception is recognized for %q with mask values: %v, %v \n", op, m1, m2)
+ }
+ switch inst.Op {
+ case VSTRC:
+ args[0], args[1], args[2], args[3] = args[1], args[2], args[3], args[0]
+ default:
+ args[0], args[1], args[2] = args[1], args[2], args[0]
+ }
+ args = args[:3+off]
+
+ case VCEQ, VCH, VCHL: // Mnemonic V1, V2, V3, M4, M5
+ m4, err := strconv.Atoi(args[3][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: %q error in converting Atoi:%s", op, err)
+ }
+ m5, err := strconv.Atoi(args[4][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: %q error in converting Atoi:%s", op, err)
+ }
+ val := (m4 & 0x7)
+ if m5 == 0 {
+ if val >= 0 && val < 4 {
+ op = op + vectorSize[val]
+ args[0], args[1], args[2] = args[1], args[2], args[0]
+ args = args[:3]
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask(m4) value: %v \n", op, m4)
+ }
+ } else if m5 == 1 {
+ if val >= 0 && val < 4 {
+ op = op + vectorCS[val]
+ args[0], args[1], args[2] = args[1], args[2], args[0]
+ args = args[:3]
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask(m4) value: %v \n", op, m4)
+ }
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask(m5) value: %v \n", op, m5)
+ }
+ case VFMA, VFMS, VMSL: //Mnemonic V1, V2, V3, V4, M5, M6
+ m5, err := strconv.Atoi(args[4][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: %q error in converting Atoi:%s", op, err)
+ }
+ m6, err := strconv.Atoi(args[5][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: %q error in converting Atoi:%s", op, err)
+ }
+ switch inst.Op {
+ case VMSL:
+ if m5 == 3 && m6 == 8 {
+ op = op + "EG"
+ } else if m5 == 3 && m6 == 4 {
+ op = op + "OG"
+ } else if m5 == 3 && m6 == 12 {
+ op = op + "EOG"
+ } else if m5 == 3 {
+ op = op + "G"
+ }
+ default:
+ if m5 == 0 && m6 == 3 {
+ op = op + "DB"
+ } else if m5 == 8 && m6 == 3 {
+ op = "W" + op[1:] + "DB"
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with m5: %v m6: %v \n", op, m5, m6)
+ }
+ }
+ args[0], args[1], args[2], args[3] = args[1], args[2], args[3], args[0]
+ args = args[:4]
+
+ case VFCE, VFCH, VFCHE: //Mnemonic V1,V2,V3,M4,M5,M6
+ m4, err := strconv.Atoi(args[3][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: %q error in converting Atoi:%s", op, err)
+ }
+ m5, err := strconv.Atoi(args[4][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: %q error in converting Atoi:%s", op, err)
+ }
+ m6, err := strconv.Atoi(args[5][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: %q error in converting Atoi:%s", op, err)
+ }
+ if m5 == 0 {
+ if m4 == 3 && m6 == 0 {
+ op = op + "DB"
+ } else if m4 == 3 && m6 == 1 {
+ op = op + "DBS"
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with m4: %v, m6: %v \n", op, m4, m6)
+ }
+
+ } else if m5 == 8 {
+ if m4 == 3 && m6 == 0 {
+ op = "W" + op[1:] + "DB"
+ } else if m4 == 3 && m6 == 1 {
+ op = "W" + op[1:] + "DBS"
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with m4: %v, m6: %v \n", op, m4, m6)
+ }
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with m5: %v \n", op, m5)
+ }
+ args[0], args[1], args[2] = args[1], args[2], args[0]
+ args = args[:3]
+
+ case VFTCI:
+ m4, err := strconv.Atoi(args[3][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: %q error in converting Atoi:%s", op, err)
+ }
+ m5, err := strconv.Atoi(args[4][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: %q error in converting Atoi:%s", op, err)
+ }
+ val := (m4 & 0x7)
+ if m5 == 0 {
+ switch val {
+ case 2:
+ op = op + "SB"
+ case 3:
+ op = op + "DB"
+ default:
+ return fmt.Sprintf("specification exception is recognized for %q with mask(m4) value: %v \n", op, m4)
+ }
+ } else if m5 == 8 {
+ switch val {
+ case 2:
+ op = "W" + op[1:] + "SB"
+ case 3:
+ op = "W" + op[1:] + "DB"
+ case 4:
+ op = "W" + op[1:] + "XB"
+ default:
+ return fmt.Sprintf("specification exception is recognized for %q with mask(m4) value: %v \n", op, m4)
+ }
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask(m5) value: %v \n", op, m5)
+ }
+ args[0], args[1], args[2] = args[2], args[1], args[0]
+ args = args[:3]
+ case VAC, VACCC:
+ mask, err := strconv.Atoi(args[4][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ if mask&0x04 == 0 {
+ return fmt.Sprintf("specification exception is recognized for %q with mask value: %v \n", op, mask)
+ }
+ op = op + "Q"
+ args[0], args[1], args[2], args[3] = args[1], args[2], args[3], args[0]
+ args = args[:4]
+ case VL, VLREP:
+ switch inst.Op {
+ case VL:
+ args[0], args[1] = args[1], args[0]
+ case VLREP:
+ args[0], args[1] = args[1], args[0]
+ mask, err := strconv.Atoi(args[2][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ if mask >= 0 && mask < 4 {
+ op = op + vectorSize[mask]
+ }
+ }
+ args = args[:2]
+ case VST, VSTEB, VSTEH, VSTEF, VSTEG, VLEB, VLEH, VLEF, VLEG: //Mnemonic V1, D2(X2,B2), M3
+ m, err := strconv.Atoi(args[2][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ switch inst.Op {
+ case VST:
+ if m == 0 || (m > 2 && m < 5) {
+ args = args[:2]
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask value: %v \n", op, m)
+ }
+ case VLEB, VLEH, VLEF, VLEG:
+ args[0], args[2] = args[2], args[0]
+ default:
+ args[0], args[1], args[2] = args[2], args[0], args[1]
+ }
+ case VSTM, VSTL, VESL, VESRA, VLM, VERLL, VLVG: //Mnemonic V1, V3, D2(B2)[,M4] or V1, R3,D2(B2)
+ switch inst.Op {
+ case VSTM, VLM:
+ m, err := strconv.Atoi(args[3][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ if !(m == 0 || (m > 2 && m < 5)) {
+ return fmt.Sprintf("specification exception is recognized for %q with mask value: %v \n", op, m)
+ }
+ if inst.Op == VLM {
+ args[0], args[1], args[2] = args[2], args[0], args[1]
+ }
+ args = args[:3]
+ case VESL, VESRA, VERLL, VLVG:
+ m, err := strconv.Atoi(args[3][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ if m >= 0 && m < 4 {
+ op = op + vectorSize[m]
+ } else {
+ return fmt.Sprintf("specification exception is recognized for %q with mask value: %v \n", op, m)
+ }
+ switch inst.Op {
+ case VLVG:
+ args[0], args[2] = args[2], args[0]
+ args = args[:3]
+ default:
+ if args[0] == args[1] {
+ args[0], args[1] = args[2], args[1]
+ args = args[:2]
+ break
+ }
+ args[0], args[2] = args[2], args[0]
+ args = args[:3]
+ }
+ case VSTL:
+ args[0], args[1] = args[1], args[0]
+ args = args[:3]
+ }
+ case VGBM:
+ val, err := strconv.Atoi(args[1][1:])
+ if err != nil {
+ return fmt.Sprintf("GoSyntax: error in converting Atoi:%s", err)
+ }
+ if val == 0 {
+ op = "VZERO"
+ args = args[:1]
+ } else if val == 0xffff {
+ op = "VONE"
+ args = args[:1]
+ } else {
+ args[0], args[1] = args[1], args[0]
+ args = args[:2]
+ }
+ case VN, VNC, VO, VX, VNO: //mnemonic V1, V2, V3
+ if args[0] == args[2] {
+ args = args[:2]
+ args[0], args[1] = args[1], args[0]
+ } else {
+ args[0], args[1], args[2] = args[1], args[2], args[0]
+ }
+ if op == "VNO" {
+ op = op + "T"
+ }
+ case VGEG, VGEF, VSCEG, VSCEF: //Mnemonic V1, D2(V2, B2), M3
+ args[0], args[2] = args[2], args[0]
+
+ }
+ if args != nil {
+ op += " " + strings.Join(args, ", ")
+ }
+
+ return op
+}
+
+// This function returns corresponding extended mnemonic for the given
+// branch on relative mnemonic.
+func branch_relative_op(mask int, opconst Op) (op string, check bool) {
+ switch mask & 0xf {
+ case 2:
+ op = "BGT"
+ check = true
+ case 4:
+ op = "BLT"
+ check = true
+ case 5:
+ op = "BLTU"
+ check = true
+ case 7:
+ op = "BNE"
+ check = true
+ case 8:
+ op = "BEQ"
+ check = true
+ case 10:
+ op = "BGE"
+ check = true
+ case 12:
+ op = "BLE"
+ check = true
+ case 13:
+ op = "BLEU"
+ check = true
+ case 15:
+ op = "JMP" // BR
+ check = true
+ }
+ return op, check
+}
+
+// This function returns corresponding extended mnemonic for the given
+// brach on condition mnemonic.
+func branchOnConditionOp(mask int, opconst Op) (op string, check bool) {
+ switch mask & 0xf {
+ case 0:
+ op = "NOPH"
+ case 14:
+ op = "SYNC"
+ case 15:
+ op = "JMP"
+ check = true
+ }
+ return op, check
+}
+
+// This function returns corresponding plan9 mnemonic for the native bitwise mnemonic.
+func bitwise_op(op Op) string {
+ var ret string
+ switch op {
+ case NGR, NGRK, NILL:
+ ret = "AND"
+ case NR, NRK, NILH, NILF:
+ ret = "ANDW"
+ case OGR, OGRK, OILF:
+ ret = "OR"
+ case OR, ORK, OILH, OILL:
+ ret = "ORW"
+ case XGR, XGRK, XILF:
+ ret = "XOR"
+ case XR, XRK:
+ ret = "XORW"
+ }
+ return ret
+}
+
+// This function parses memory operand of type D(B)
+func mem_operand(args []string) string {
+ if args[0] != "" && args[1] != "" {
+ args[0] = fmt.Sprintf("%s(%s)", args[0], args[1])
+ } else if args[0] != "" {
+ args[0] = fmt.Sprintf("$%s", args[0])
+ } else if args[1] != "" {
+ args[0] = fmt.Sprintf("(%s)", args[1])
+ } else {
+ args[0] = ""
+ }
+ return args[0]
+}
+
+// This function parses memory operand of type D(X,B)
+func mem_operandx(args []string) string {
+ if args[1] != "" && args[2] != "" {
+ args[1] = fmt.Sprintf("(%s)(%s*1)", args[2], args[1])
+ } else if args[1] != "" {
+ args[1] = fmt.Sprintf("(%s)", args[1])
+ } else if args[2] != "" {
+ args[1] = fmt.Sprintf("(%s)", args[2])
+ } else if args[0] != "" {
+ args[1] = ""
+ }
+ if args[0] != "" && args[1] != "" {
+ args[0] = fmt.Sprintf("%s%s", args[0], args[1])
+ } else if args[0] != "" {
+ args[0] = fmt.Sprintf("$%s", args[0])
+ } else if args[1] != "" {
+ args[0] = fmt.Sprintf("%s", args[1])
+ } else {
+ args[0] = ""
+ }
+ return args[0]
+}
+
+// This function parses memory operand of type D(V,B)
+func mem_operandv(args []string) string {
+ if args[1] != "" && args[2] != "" {
+ args[1] = fmt.Sprintf("(%s)(%s*1)", args[2], args[1])
+ } else if args[1] != "" {
+ args[1] = fmt.Sprintf("(%s*1)", args[1])
+ } else if args[2] != "" {
+ args[1] = fmt.Sprintf("(%s)", args[2])
+ } else if args[0] != "" {
+ args[1] = ""
+ }
+ if args[0] != "" && args[1] != "" {
+ args[0] = fmt.Sprintf("%s%s", args[0], args[1])
+ } else if args[0] != "" {
+ args[0] = fmt.Sprintf("$%s", args[0])
+ } else if args[1] != "" {
+ args[0] = fmt.Sprintf("%s", args[1])
+ } else {
+ args[0] = ""
+ }
+ return args[0]
+}
+
+// This function parses memory operand of type D(L,B)
+func mem_operandl(args []string) (string, string) {
+ if args[0] != "" && args[2] != "" {
+ args[0] = fmt.Sprintf("%s(%s)", args[0], args[2])
+ } else if args[2] != "" {
+ args[0] = fmt.Sprintf("(%s)", args[2])
+ } else {
+ args[0] = fmt.Sprintf("%s", args[0])
+ }
+ return args[0], args[1]
+}
+
+// plan9Arg formats arg (which is the argIndex's arg in inst) according to Plan 9 rules.
+// NOTE: because Plan9Syntax is the only caller of this func, and it receives a copy
+// of inst, it's ok to modify inst.Args here.
+func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
+ switch arg.(type) {
+ case Reg:
+ if arg == R13 {
+ return "g"
+ }
+ return strings.ToUpper(arg.String(pc)[1:])
+ case Base:
+ if arg == R13 {
+ return "g"
+ }
+ s := arg.String(pc)
+ if s != "" {
+ return strings.ToUpper(s[1 : len(s)-1])
+ }
+ return "R0"
+ case Index:
+ if arg == R13 {
+ return "g"
+ }
+ s := arg.String(pc)
+ if s != "" {
+ return strings.ToUpper(s[1:])
+ }
+ return ""
+ case VReg:
+ return strings.ToUpper(arg.String(pc)[1:])
+ case Disp20, Disp12:
+ numstr := arg.String(pc)
+ num, err := strconv.Atoi(numstr[:len(numstr)])
+ if err != nil {
+ return fmt.Sprintf("plan9Arg: error in converting Atoi:%s", err)
+ }
+ if num == 0 {
+ return ""
+ } else {
+ return strconv.Itoa(num)
+ }
+ case RegIm12, RegIm16, RegIm24, RegIm32:
+ addr, err := strconv.ParseUint(arg.String(pc)[2:], 16, 64)
+ if err != nil {
+ return fmt.Sprintf("plan9Arg: error in converting ParseUint:%s", err)
+ }
+ off := int(addr - pc)
+ s, base := symname(addr)
+ if s != "" && addr == base {
+ return fmt.Sprintf("%s(SB)", s)
+ }
+ off = off / inst.Len
+ return fmt.Sprintf("%v(PC)", off)
+ case Imm, Sign8, Sign16, Sign32:
+ numImm := arg.String(pc)
+ switch arg.(type) {
+ case Sign32, Sign16, Imm:
+ num, err := strconv.ParseInt(numImm, 10, 64)
+ if err != nil {
+ return fmt.Sprintf("plan9Arg: error in converting ParseInt:%s", err)
+ }
+ switch inst.Op {
+ case LLIHF:
+ num = num << 32
+ case LLILH:
+ num = num << 16
+ case NILH:
+ num = (num << 16) | int64(0xFFFF)
+ case OILH:
+ num = num << 16
+ }
+ numImm = fmt.Sprintf("%d", num)
+ }
+ return fmt.Sprintf("$%s", numImm)
+ case Mask, Len:
+ num := arg.String(pc)
+ return fmt.Sprintf("$%s", num)
+ }
+ return fmt.Sprintf("???(%v)", arg)
+}
+
+// It checks any 2 args of given instructions to swap or not
+func reverseOperandOrder(op Op) bool {
+ switch op {
+ case LOCR, MLGR:
+ return true
+ case LTEBR, LTDBR:
+ return true
+ case VLEIB, VLEIH, VLEIF, VLEIG, VPDI:
+ return true
+ case VSLDB:
+ return true
+ }
+ return false
+}
+
+// It checks whether to reverse all the args of given mnemonic or not
+func reverseAllOperands(op Op) bool {
+ switch op {
+ case VLVGP: //3-operand list
+ return true
+ case VSEL, VPERM: //4-Operand list
+ return true
+ }
+ return false
+}
diff --git a/s390x/s390xasm/testdata/decode.txt b/s390x/s390xasm/testdata/decode.txt
new file mode 100644
index 0000000..f04715b
--- /dev/null
+++ b/s390x/s390xasm/testdata/decode.txt
@@ -0,0 +1,162 @@
+ b9040021| plan9 MOVD R1, R2
+ b9140043| plan9 MOVW R3, R4
+ b9070065| plan9 MOVH R5, R6
+ b9060087| plan9 MOVB R7, R8
+ b9160021| plan9 MOVWZ R1, R2
+ b9850032| plan9 MOVHZ R2, R3
+ b9840054| plan9 MOVBZ R4, R5
+ b90f0021| plan9 MOVDBR R1, R2
+ b91f0043| plan9 MOVWBR R3, R4
+ b9e28010| plan9 MOVDEQ R0, R1
+ b9e2a032| plan9 MOVDGE R2, R3
+ b9e22054| plan9 MOVDGT R4, R5
+ b9e2c076| plan9 MOVDLE R6, R7
+ b9e24098| plan9 MOVDLT R8, R9
+ b9e270ba| plan9 MOVDNE R10, R11
+ b9f23012| plan9 LOCR $3, R2, R1
+ b9e27065| plan9 MOVDNE R5, R6
+e310f0000004| plan9 MOVD (R15), R1
+e320f0000014| plan9 MOVW (R15), R2
+e330f0000015| plan9 MOVH (R15), R3
+e340f0000077| plan9 MOVB (R15), R4
+e350f0000016| plan9 MOVWZ (R15), R5
+e360f0000091| plan9 MOVHZ (R15), R6
+e370f0000090| plan9 MOVBZ (R15), R7
+e380f000000f| plan9 MOVDBR (R15), R8
+e390f000001e| plan9 MOVWBR (R15), R9
+e310fff8ff24| plan9 MOVD R1, -8(R15)
+e320fff8ff50| plan9 MOVW R2, -8(R15)
+e330fff8ff70| plan9 MOVH R3, -8(R15)
+e340fff8ff72| plan9 MOVB R4, -8(R15)
+e350fff8ff2f| plan9 MOVDBR R5, -8(R15)
+e360fff8ff3e| plan9 MOVWBR R6, -8(R15)
+c01efffffffe| plan9 MOVD $-8589934592, R1
+c021fffe0000| plan9 MOVW $-131072, R2
+ a739fe00| plan9 MOVH $-512, R3
+ a749ffff| plan9 MOVB $-1, R4
+ b9e81022| plan9 ADD R1, R2
+ b9e81032| plan9 ADD R1, R2, R3
+ a71b2000| plan9 ADD $8192, R1
+ec21200000d9| plan9 ADD $8192, R1, R2
+c21800008000| plan9 ADD $32768, R1
+ b9ea1022| plan9 ADDC R1, R2
+ b9ea1032| plan9 ADDC R1, R2, R3
+ec21000100db| plan9 ADDC $1, R1, R2
+ec21ffff00db| plan9 SUBC $1, R1, R2
+ 1a21| plan9 ADDW R1, R2
+ b9f81032| plan9 ADDW R1, R2, R3
+ a71a2000| plan9 ADDW $8192, R1
+ec21200000d8| plan9 ADDW $8192, R1, R2
+ b9880021| plan9 ADDE R1, R2
+e3201000000a| plan9 ADDC (R1), R2
+ 5a605000| plan9 ADDW (R5), R6
+ 5a807fff| plan9 ADDW 4095(R7), R8
+e3201fffff5a| plan9 ADDW -1(R1), R2
+e34030000188| plan9 ADDE 4096(R3), R4
+e34230000188| plan9 ADDE 4096(R3)(R2*1), R4
+ b9090043| plan9 SUB R3, R4
+ b9e93054| plan9 SUB R3, R4, R5
+ a73be000| plan9 SUB $8192, R3
+ec43e00000d9| plan9 SUB $8192, R3, R4
+ b90b0021| plan9 SUBC R1, R2
+ec43ffff00db| plan9 SUBC $1, R3, R4
+ b9eb2043| plan9 SUBC R2, R3, R4
+ 1b43| plan9 SUBW R3, R4
+ b9f93054| plan9 SUBW R3, R4, R5
+c21500002000| plan9 SUBW $8192, R1
+e320400f0089| plan9 SUBE 15(R4), R2
+e32040080009| plan9 SUB 8(R4), R2
+ 5b204000| plan9 SUBW (R4), R2
+e3204fffff5b| plan9 SUBW -1(R4), R2
+ b91c0076| plan9 MULLW R6, R7
+ a76c2000| plan9 MULLW $8192, R6
+c2810000000f| plan9 MULLW $15, R8
+c281ffff7fff| plan9 MULLW $-32769, R8
+c21080000000| plan9 MULLD $-2147483648, R1
+ b9860021| plan9 MLGR R1, R2
+ b9030011| plan9 NEG R1
+ b9030021| plan9 NEG R1, R2
+ b9130011| plan9 NEGW R1
+ b9130021| plan9 NEGW R1, R2
+ b9830022| plan9 FLOGR R2, R2
+ b9800021| plan9 AND R1, R2
+ b9e42031| plan9 AND R1, R2, R3
+ a517ffff| plan9 ANDW $-1, R1
+c01bffff0000| plan9 AND $-65536, R1
+ 1421| plan9 ANDW R1, R2
+ b9f42031| plan9 ANDW R1, R2, R3
+c01b00000001| plan9 ANDW $1, R1
+ a5160001| plan9 ANDW $131071, R1
+c01b00010000| plan9 ANDW $65536, R1
+ a517fffe| plan9 ANDW $-2, R1
+ a517000f| plan9 AND $15, R1
+e32010000080| plan9 AND (R1), R2
+ 54201000| plan9 ANDW (R1), R2
+e32010000154| plan9 ANDW 4096(R1), R2
+ b9810021| plan9 OR R1, R2
+ b9e62031| plan9 OR R1, R2, R3
+ a51a0001| plan9 ORW $65536, R1
+ a51bffff| plan9 ORW $-1, R1
+ a51b0001| plan9 ORW $1, R1
+ 1621| plan9 ORW R1, R2
+c01d0001ffff| plan9 OR $131071, R1
+c01dffffffff| plan9 ORW $-1, R1
+ b9f62031| plan9 ORW R1, R2, R3
+e32010000081| plan9 OR (R1), R2
+ 56201000| plan9 ORW (R1), R2
+e3201fffff56| plan9 ORW -1(R1), R2
+ b9820021| plan9 XOR R1, R2
+ b9e72031| plan9 XOR R1, R2, R3
+c01700000001| plan9 XOR $1, R1
+c0170001ffff| plan9 XOR $131071, R1
+c01700010000| plan9 XOR $65536, R1
+ 1721| plan9 XORW R1, R2
+ b9f72031| plan9 XORW R1, R2, R3
+c017fffffffe| plan9 XORW $-2, R1
+ 0700| plan9 NOPH
+ 07e0| plan9 SYNC
+ b92e0024| plan9 KM R2, R4
+ b92f0026| plan9 KMC R2, R6
+ b93f0028| plan9 KLMD R2, R8
+ b93e0004| plan9 KIMD R0, R4
+ b93a0008| plan9 KDSA R0, R8
+ b9296024| plan9 KMA R2, R6, R4
+ b92d6024| plan9 KMCTR R2, R6, R4
+e743400000f3| plan9 VAB V3, V4
+e743600000f3| plan9 VAB V3, V6, V4
+e743400010f3| plan9 VAH V3, V4
+e743600010f3| plan9 VAH V3, V6, V4
+e743400020f3| plan9 VAF V3, V4
+e743600020f3| plan9 VAF V3, V6, V4
+e743400030f3| plan9 VAG V3, V4
+e743600030f3| plan9 VAG V3, V6, V4
+e743400040f3| plan9 VAQ V3, V4
+e743600040f3| plan9 VAQ V3, V6, V4
+e734600000f7| plan9 VSB V6, V4, V3
+e722100000f7| plan9 VSB V1, V2
+e734600010f7| plan9 VSH V6, V4, V3
+e722100010f7| plan9 VSH V1, V2
+e734600020f7| plan9 VSF V6, V4, V3
+e722100020f7| plan9 VSF V1, V2
+e734600030f7| plan9 VSG V6, V4, V3
+e722100030f7| plan9 VSG V1, V2
+e734600040f7| plan9 VSQ V6, V4, V3
+e722100040f7| plan9 VSQ V1, V2
+e7824000608a| plan9 VSTRCB V2, V4, V6, V8
+e7824100608a| plan9 VSTRCH V2, V4, V6, V8
+e7824200608a| plan9 VSTRCF V2, V4, V6, V8
+e7824010608a| plan9 VSTRCBS V2, V4, V6, V8
+e7824110608a| plan9 VSTRCHS V2, V4, V6, V8
+e7824210608a| plan9 VSTRCFS V2, V4, V6, V8
+e710ffff0044| plan9 VONE V1
+e70000000844| plan9 VZERO V16
+e70210000068| plan9 VN V2, V1, V0
+e71010000468| plan9 VN V16, V1
+e70210000069| plan9 VNC V2, V1, V0
+e71010000469| plan9 VNC V16, V1
+e7021000006a| plan9 VO V2, V1, V0
+e7101000046a| plan9 VO V16, V1
+e7021000006d| plan9 VX V2, V1, V0
+e7101000046d| plan9 VX V16, V1
+e7101000046b| plan9 VNOT V16, V1
+e78340000062| plan9 VLVGP R3, R4, V8