arm/armasm: Improve Plan 9 syntax decoding

The arm disassembler can not decode many instructions to
correct Plan 9 syntax.

This patch fixes 3 major issues.

1. Change memory addresses in PLD/PLI/SWP/STREX/LDREX to the correct
Plan 9 syntax (in accordance with MOVW/MOVB/MOVH). For example,
   [rx] -> (Rx)
   [rx, #imm] -> imm(Rx)
   [rx, ry, lsl #imm] -> (Rx)(Ry<<imm)

2. Apply the Plan 9 syntax naming rule to more instructions. Such as,
   VMRS -> MOVW
   VMSR -> MOVW
   XTB  -> MOVBS
   XTHU -> MOVHU
   XTH  -> MOVHS
   XTBU -> MOVBU

3. Improve FP instructions decoding.
   3.1 instruction name: VADD.F32 -> ADDF, VSUB.F64 -> SUBD, ...
   3.2 register name: S0 -> F0, D0 -> F0, S2 -> F1, D1 -> F1, ...

Many test cases are also changed.

Change-Id: I5f8ac0e82c6edec2f4bdc4db58f6bcbab40d299a
Reviewed-on: https://go-review.googlesource.com/85455
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/arm/armasm/plan9x.go b/arm/armasm/plan9x.go
index 321b081..a143d2e 100644
--- a/arm/armasm/plan9x.go
+++ b/arm/armasm/plan9x.go
@@ -96,34 +96,24 @@
 	// Move addressing mode into opcode suffix.
 	suffix := ""
 	switch inst.Op &^ 15 {
-	case LDR_EQ, LDRB_EQ, LDRSB_EQ, LDRH_EQ, LDRSH_EQ, STR_EQ, STRB_EQ, STRH_EQ, VLDR_EQ, VSTR_EQ:
-		mem, _ := inst.Args[1].(Mem)
-		switch mem.Mode {
-		case AddrOffset, AddrLDM:
-			// no suffix
-		case AddrPreIndex, AddrLDM_WB:
-			suffix = ".W"
-		case AddrPostIndex:
-			suffix = ".P"
+	case PLD, PLI, PLD_W:
+		if mem, ok := inst.Args[0].(Mem); ok {
+			args[0], suffix = memOpTrans(mem)
+		} else {
+			panic(fmt.Sprintf("illegal instruction: %v", inst))
 		}
-		off := ""
-		if mem.Offset != 0 {
-			off = fmt.Sprintf("%#x", mem.Offset)
+	case LDR_EQ, LDRB_EQ, LDRSB_EQ, LDRH_EQ, LDRSH_EQ, STR_EQ, STRB_EQ, STRH_EQ, VLDR_EQ, VSTR_EQ, LDREX_EQ, LDREXH_EQ, LDREXB_EQ:
+		if mem, ok := inst.Args[1].(Mem); ok {
+			args[1], suffix = memOpTrans(mem)
+		} else {
+			panic(fmt.Sprintf("illegal instruction: %v", inst))
 		}
-		base := fmt.Sprintf("(R%d)", int(mem.Base))
-		index := ""
-		if mem.Sign != 0 {
-			sign := ""
-			if mem.Sign < 0 {
-				suffix += ".U"
-			}
-			shift := ""
-			if mem.Count != 0 {
-				shift = fmt.Sprintf("%s%d", plan9Shift[mem.Shift], mem.Count)
-			}
-			index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift)
+	case SWP_EQ, SWP_B_EQ, STREX_EQ, STREXB_EQ, STREXH_EQ:
+		if mem, ok := inst.Args[2].(Mem); ok {
+			args[2], suffix = memOpTrans(mem)
+		} else {
+			panic(fmt.Sprintf("illegal instruction: %v", inst))
 		}
-		args[1] = off + base + index
 	}
 
 	// Reverse args, placing dest last.
@@ -135,35 +125,35 @@
 	case SMLAWT_EQ, SMLAWB_EQ, MLA_EQ, MLA_S_EQ, MLS_EQ, SMMLA_EQ, SMMLS_EQ, SMLABB_EQ, SMLATB_EQ, SMLABT_EQ, SMLATT_EQ, SMLAD_EQ, SMLAD_X_EQ, SMLSD_EQ, SMLSD_X_EQ:
 		args = []string{args[1], args[2], args[0], args[3]}
 	}
+	// For STREX like instructions, the memory operands comes first.
+	switch inst.Op &^ 15 {
+	case STREX_EQ, STREXB_EQ, STREXH_EQ, SWP_EQ, SWP_B_EQ:
+		args = []string{args[1], args[0], args[2]}
+	}
 
+	// special process for FP instructions
+	op, args = fpTrans(&inst, op, args)
+
+	// LDR/STR like instructions -> MOV like
 	switch inst.Op &^ 15 {
 	case MOV_EQ:
 		op = "MOVW" + op[3:]
-
-	case LDR_EQ:
+	case LDR_EQ, MSR_EQ, MRS_EQ:
 		op = "MOVW" + op[3:] + suffix
-	case LDRB_EQ:
+	case VMRS_EQ, VMSR_EQ:
+		op = "MOVW" + op[4:] + suffix
+	case LDRB_EQ, UXTB_EQ:
 		op = "MOVBU" + op[4:] + suffix
 	case LDRSB_EQ:
 		op = "MOVBS" + op[5:] + suffix
-	case LDRH_EQ:
+	case SXTB_EQ:
+		op = "MOVBS" + op[4:] + suffix
+	case LDRH_EQ, UXTH_EQ:
 		op = "MOVHU" + op[4:] + suffix
 	case LDRSH_EQ:
 		op = "MOVHS" + op[5:] + suffix
-	case VLDR_EQ:
-		switch {
-		case strings.HasPrefix(args[1], "D"): // VLDR.F64
-			op = "MOVD" + op[4:] + suffix
-			args[1] = "F" + args[1][1:] // Dx -> Fx
-		case strings.HasPrefix(args[1], "S"): // VLDR.F32
-			op = "MOVF" + op[4:] + suffix
-			if inst.Args[0].(Reg)&1 == 0 { // Sx -> Fy, y = x/2, if x is even
-				args[1] = fmt.Sprintf("F%d", (inst.Args[0].(Reg)-S0)/2)
-			}
-		default:
-			panic(fmt.Sprintf("wrong FP register: %v", inst))
-		}
-
+	case SXTH_EQ:
+		op = "MOVHS" + op[4:] + suffix
 	case STR_EQ:
 		op = "MOVW" + op[3:] + suffix
 		args[0], args[1] = args[1], args[0]
@@ -174,19 +164,9 @@
 		op = "MOVH" + op[4:] + suffix
 		args[0], args[1] = args[1], args[0]
 	case VSTR_EQ:
-		switch {
-		case strings.HasPrefix(args[1], "D"): // VSTR.F64
-			op = "MOVD" + op[4:] + suffix
-			args[1] = "F" + args[1][1:] // Dx -> Fx
-		case strings.HasPrefix(args[1], "S"): // VSTR.F32
-			op = "MOVF" + op[4:] + suffix
-			if inst.Args[0].(Reg)&1 == 0 { // Sx -> Fy, y = x/2, if x is even
-				args[1] = fmt.Sprintf("F%d", (inst.Args[0].(Reg)-S0)/2)
-			}
-		default:
-			panic(fmt.Sprintf("wrong FP register: %v", inst))
-		}
 		args[0], args[1] = args[1], args[0]
+	default:
+		op = op + suffix
 	}
 
 	if args != nil {
@@ -266,3 +246,153 @@
 	}
 	return strings.ToUpper(arg.String())
 }
+
+// convert memory operand from GNU syntax to Plan 9 syntax, for example,
+// [r5] -> (R5)
+// [r6, #4080] -> 0xff0(R6)
+// [r2, r0, ror #1] -> (R2)(R0@>1)
+// inst [r2, -r0, ror #1] -> INST.U (R2)(R0@>1)
+// input:
+//   a memory operand
+// return values:
+//   corresponding memory operand in Plan 9 syntax
+//   .W/.P/.U suffix
+func memOpTrans(mem Mem) (string, string) {
+	suffix := ""
+	switch mem.Mode {
+	case AddrOffset, AddrLDM:
+		// no suffix
+	case AddrPreIndex, AddrLDM_WB:
+		suffix = ".W"
+	case AddrPostIndex:
+		suffix = ".P"
+	}
+	off := ""
+	if mem.Offset != 0 {
+		off = fmt.Sprintf("%#x", mem.Offset)
+	}
+	base := fmt.Sprintf("(R%d)", int(mem.Base))
+	index := ""
+	if mem.Sign != 0 {
+		sign := ""
+		if mem.Sign < 0 {
+			suffix += ".U"
+		}
+		shift := ""
+		if mem.Count != 0 {
+			shift = fmt.Sprintf("%s%d", plan9Shift[mem.Shift], mem.Count)
+		}
+		index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift)
+	}
+	return off + base + index, suffix
+}
+
+type goFPInfo struct {
+	op        Op
+	transArgs []int  // indexes of arguments which need transformation
+	gnuName   string // instruction name in GNU syntax
+	goName    string // instruction name in Plan 9 syntax
+}
+
+var fpInst []goFPInfo = []goFPInfo{
+	{VADD_EQ_F32, []int{2, 1, 0}, "VADD", "ADDF"},
+	{VADD_EQ_F64, []int{2, 1, 0}, "VADD", "ADDD"},
+	{VSUB_EQ_F32, []int{2, 1, 0}, "VSUB", "SUBF"},
+	{VSUB_EQ_F64, []int{2, 1, 0}, "VSUB", "SUBD"},
+	{VMUL_EQ_F32, []int{2, 1, 0}, "VMUL", "MULF"},
+	{VMUL_EQ_F64, []int{2, 1, 0}, "VMUL", "MULD"},
+	{VNMUL_EQ_F32, []int{2, 1, 0}, "VNMUL", "NMULF"},
+	{VNMUL_EQ_F64, []int{2, 1, 0}, "VNMUL", "NMULD"},
+	{VMLA_EQ_F32, []int{2, 1, 0}, "VMLA", "MULAF"},
+	{VMLA_EQ_F64, []int{2, 1, 0}, "VMLA", "MULAD"},
+	{VMLS_EQ_F32, []int{2, 1, 0}, "VMLS", "MULSF"},
+	{VMLS_EQ_F64, []int{2, 1, 0}, "VMLS", "MULSD"},
+	{VNMLA_EQ_F32, []int{2, 1, 0}, "VNMLA", "NMULAF"},
+	{VNMLA_EQ_F64, []int{2, 1, 0}, "VNMLA", "NMULAD"},
+	{VNMLS_EQ_F32, []int{2, 1, 0}, "VNMLS", "NMULSF"},
+	{VNMLS_EQ_F64, []int{2, 1, 0}, "VNMLS", "NMULSD"},
+	{VDIV_EQ_F32, []int{2, 1, 0}, "VDIV", "DIVF"},
+	{VDIV_EQ_F64, []int{2, 1, 0}, "VDIV", "DIVD"},
+	{VNEG_EQ_F32, []int{1, 0}, "VNEG", "NEGF"},
+	{VNEG_EQ_F64, []int{1, 0}, "VNEG", "NEGD"},
+	{VABS_EQ_F32, []int{1, 0}, "VABS", "ABSF"},
+	{VABS_EQ_F64, []int{1, 0}, "VABS", "ABSD"},
+	{VSQRT_EQ_F32, []int{1, 0}, "VSQRT", "SQRTF"},
+	{VSQRT_EQ_F64, []int{1, 0}, "VSQRT", "SQRTD"},
+	{VCMP_EQ_F32, []int{1, 0}, "VCMP", "CMPF"},
+	{VCMP_EQ_F64, []int{1, 0}, "VCMP", "CMPD"},
+	{VCMP_E_EQ_F32, []int{1, 0}, "VCMP.E", "CMPF"},
+	{VCMP_E_EQ_F64, []int{1, 0}, "VCMP.E", "CMPD"},
+	{VLDR_EQ, []int{1}, "VLDR", "MOV"},
+	{VSTR_EQ, []int{1}, "VSTR", "MOV"},
+	{VMOV_EQ_F32, []int{1, 0}, "VMOV", "MOVF"},
+	{VMOV_EQ_F64, []int{1, 0}, "VMOV", "MOVD"},
+	{VMOV_EQ_32, []int{1, 0}, "VMOV", "MOVW"},
+	{VMOV_EQ, []int{1, 0}, "VMOV", "MOVW"},
+	{VCVT_EQ_F64_F32, []int{1, 0}, "VCVT", "MOVFD"},
+	{VCVT_EQ_F32_F64, []int{1, 0}, "VCVT", "MOVDF"},
+	{VCVT_EQ_F32_U32, []int{1, 0}, "VCVT", "MOVWF.U"},
+	{VCVT_EQ_F32_S32, []int{1, 0}, "VCVT", "MOVWF"},
+	{VCVT_EQ_S32_F32, []int{1, 0}, "VCVT", "MOVFW"},
+	{VCVT_EQ_U32_F32, []int{1, 0}, "VCVT", "MOVFW.U"},
+	{VCVT_EQ_F64_U32, []int{1, 0}, "VCVT", "MOVWD.U"},
+	{VCVT_EQ_F64_S32, []int{1, 0}, "VCVT", "MOVWD"},
+	{VCVT_EQ_S32_F64, []int{1, 0}, "VCVT", "MOVDW"},
+	{VCVT_EQ_U32_F64, []int{1, 0}, "VCVT", "MOVDW.U"},
+}
+
+// convert FP instructions from GNU syntax to Plan 9 syntax, for example,
+// vadd.f32 s0, s3, s4 -> ADDF F0, S3, F2
+// vsub.f64 d0, d2, d4 -> SUBD F0, F2, F4
+// vldr s2, [r11] -> MOVF (R11), F1
+// inputs: instruction name and arguments in GNU syntax
+// return values: corresponding instruction name and arguments in Plan 9 syntax
+func fpTrans(inst *Inst, op string, args []string) (string, []string) {
+	for _, fp := range fpInst {
+		if inst.Op&^15 == fp.op {
+			// remove gnu syntax suffixes
+			op = strings.Replace(op, ".F32", "", -1)
+			op = strings.Replace(op, ".F64", "", -1)
+			op = strings.Replace(op, ".S32", "", -1)
+			op = strings.Replace(op, ".U32", "", -1)
+			op = strings.Replace(op, ".32", "", -1)
+			// compose op name
+			if fp.op == VLDR_EQ || fp.op == VSTR_EQ {
+				switch {
+				case strings.HasPrefix(args[fp.transArgs[0]], "D"):
+					op = "MOVD" + op[len(fp.gnuName):]
+				case strings.HasPrefix(args[fp.transArgs[0]], "S"):
+					op = "MOVF" + op[len(fp.gnuName):]
+				default:
+					panic(fmt.Sprintf("wrong FP register: %v", inst))
+				}
+			} else {
+				op = fp.goName + op[len(fp.gnuName):]
+			}
+			// transform registers
+			for ix, ri := range fp.transArgs {
+				switch {
+				case strings.HasSuffix(args[ri], "[1]"): // MOVW Rx, Dy[1]
+					break
+				case strings.HasSuffix(args[ri], "[0]"): // Dx[0] -> Fx
+					args[ri] = strings.Replace(args[ri], "[0]", "", -1)
+					fallthrough
+				case strings.HasPrefix(args[ri], "D"): // Dx -> Fx
+					args[ri] = "F" + args[ri][1:]
+				case strings.HasPrefix(args[ri], "S"):
+					if inst.Args[ix].(Reg)&1 == 0 { // Sx -> Fy, y = x/2, if x is even
+						args[ri] = fmt.Sprintf("F%d", (inst.Args[ix].(Reg)-S0)/2)
+					}
+				case strings.HasPrefix(args[ri], "$"): // CMPF/CMPD $0, Fx
+					break
+				case strings.HasPrefix(args[ri], "R"): // MOVW Rx, Dy[1]
+					break
+				default:
+					panic(fmt.Sprintf("wrong FP register: %v", inst))
+				}
+			}
+			break
+		}
+	}
+	return op, args
+}
diff --git a/arm/armasm/testdata/decode.txt b/arm/armasm/testdata/decode.txt
index f38c61f..7653ee0 100644
--- a/arm/armasm/testdata/decode.txt
+++ b/arm/armasm/testdata/decode.txt
@@ -944,44 +944,46 @@
 b12fffe6|	1	plan9	REVSH R1, R2
 312fffe6|	1	plan9	RBIT R1, R2
 112f6fe1|	1	plan9	CLZ R1, R2
-f0ffd6f5|	1	gnu	pld [r6, #4080]
-f0ff59f5|	1	gnu	pld [r9, #-4080]
-f0ff96f5|	1	gnu	pldw [r6, #4080]
-f0ff19f5|	1	gnu	pldw [r9, #-4080]
-f0ffdff5|	1	gnu	pld [pc, #4080]
-f0ff5ff5|	1	gnu	pld [pc, #-4080]
-00f0d2f7|	1	gnu	pld [r2, r0]
-00f052f7|	1	gnu	pld [r2, -r0]
-00f092f7|	1	gnu	pldw [r2, r0]
-00f012f7|	1	gnu	pldw [r2, -r0]
-80f0d2f7|	1	gnu	pld [r2, r0, lsl #1]
-80f052f7|	1	gnu	pld [r2, -r0, lsl #1]
-a0f0d2f7|	1	gnu	pld [r2, r0, lsr #1]
-a0f052f7|	1	gnu	pld [r2, -r0, lsr #1]
-c0f0d2f7|	1	gnu	pld [r2, r0, asr #1]
-c0f052f7|	1	gnu	pld [r2, -r0, asr #1]
-e0f0d2f7|	1	gnu	pld [r2, r0, ror #1]
-e0f052f7|	1	gnu	pld [r2, -r0, ror #1]
-80f092f7|	1	gnu	pldw [r2, r0, lsl #1]
-80f012f7|	1	gnu	pldw [r2, -r0, lsl #1]
-a0f092f7|	1	gnu	pldw [r2, r0, lsr #1]
-a0f012f7|	1	gnu	pldw [r2, -r0, lsr #1]
-c0f092f7|	1	gnu	pldw [r2, r0, asr #1]
-c0f012f7|	1	gnu	pldw [r2, -r0, asr #1]
-e0f092f7|	1	gnu	pldw [r2, r0, ror #1]
-e0f012f7|	1	gnu	pldw [r2, -r0, ror #1]
-f0ffd2f4|	1	gnu	pli [r2, #4080]
-f0ff52f4|	1	gnu	pli [r2, #-4080]
-82f0d3f6|	1	gnu	pli [r3, r2, lsl #1]
-82f053f6|	1	gnu	pli [r3, -r2, lsl #1]
-a2f0d3f6|	1	gnu	pli [r3, r2, lsr #1]
-a2f053f6|	1	gnu	pli [r3, -r2, lsr #1]
-c2f0d3f6|	1	gnu	pli [r3, r2, asr #1]
-c2f053f6|	1	gnu	pli [r3, -r2, asr #1]
-e2f0d3f6|	1	gnu	pli [r3, r2, ror #1]
-e2f053f6|	1	gnu	pli [r3, -r2, ror #1]
-939007e1|	1	gnu	swp r9, r3, [r7]
-948042e1|	1	gnu	swpb r8, r4, [r2]
+f0ffd6f5|	1	plan9	PLD 0xff0(R6)
+f0ff59f5|	1	plan9	PLD -0xff0(R9)
+f0ff96f5|	1	plan9	PLD.W 0xff0(R6)
+f0ff19f5|	1	plan9	PLD.W -0xff0(R9)
+f0ffdff5|	1	plan9	PLD 0xff0(R15)
+f0ff5ff5|	1	plan9	PLD -0xff0(R15)
+00f0d2f7|	1	plan9	PLD (R2)(R0)
+00f052f7|	1	plan9	PLD.U (R2)(R0)
+00f092f7|	1	plan9	PLD.W (R2)(R0)
+00f012f7|	1	plan9	PLD.W.U (R2)(R0)
+80f0d2f7|	1	plan9	PLD (R2)(R0<<1)
+80f052f7|	1	plan9	PLD.U (R2)(R0<<1)
+a0f0d2f7|	1	plan9	PLD (R2)(R0>>1)
+a0f052f7|	1	plan9	PLD.U (R2)(R0>>1)
+c0f0d2f7|	1	plan9	PLD (R2)(R0->1)
+c0f052f7|	1	plan9	PLD.U (R2)(R0->1)
+e0f0d2f7|	1	plan9	PLD (R2)(R0@>1)
+e0f052f7|	1	plan9	PLD.U (R2)(R0@>1)
+80f092f7|	1	plan9	PLD.W (R2)(R0<<1)
+80f012f7|	1	plan9	PLD.W.U (R2)(R0<<1)
+a0f092f7|	1	plan9	PLD.W (R2)(R0>>1)
+a0f012f7|	1	plan9	PLD.W.U (R2)(R0>>1)
+c0f092f7|	1	plan9	PLD.W (R2)(R0->1)
+c0f012f7|	1	plan9	PLD.W.U (R2)(R0->1)
+e0f092f7|	1	plan9	PLD.W (R2)(R0@>1)
+e0f012f7|	1	plan9	PLD.W.U (R2)(R0@>1)
+f0ffd2f4|	1	plan9	PLI 0xff0(R2)
+f0ff52f4|	1	plan9	PLI -0xff0(R2)
+00f0d2f6|	1	plan9	PLI (R2)(R0)
+00f052f6|	1	plan9	PLI.U (R2)(R0)
+82f0d3f6|	1	plan9	PLI (R3)(R2<<1)
+82f053f6|	1	plan9	PLI.U (R3)(R2<<1)
+a2f0d3f6|	1	plan9	PLI (R3)(R2>>1)
+a2f053f6|	1	plan9	PLI.U (R3)(R2>>1)
+c2f0d3f6|	1	plan9	PLI (R3)(R2->1)
+c2f053f6|	1	plan9	PLI.U (R3)(R2->1)
+e2f0d3f6|	1	plan9	PLI (R3)(R2@>1)
+e2f053f6|	1	plan9	PLI.U (R3)(R2@>1)
+939007e1|	1	plan9	SWP R3, (R7), R9
+948042e1|	1	plan9	SWP.B R4, (R2), R8
 000000ef|	1	plan9	SVC $0
 ffff00ef|	1	plan9	SVC $65535
 ff10e0e3|	1	plan9	MVN $255, R1
@@ -1061,15 +1063,15 @@
 201012e5|	1	plan9	MOVW -0x20(R2), R1
 201012e4|	1	plan9	MOVW.P -0x20(R2), R1
 201032e5|	1	plan9	MOVW.W -0x20(R2), R1
-00100fe1|	1	plan9	MRS APSR, R1
-fef02ce3|	1	plan9	MSR $254, APSR
-fff42ce3|	1	plan9	MSR $4278190080, APSR
-05f02c01|	1	plan9	MSR.EQ R5, APSR
-09f02c11|	1	plan9	MSR.NE R9, APSR
-109af1ee|	1	plan9	VMRS FPSCR, R9
-10aaf1ee|	1	plan9	VMRS FPSCR, R10
-109ae1ee|	1	plan9	VMSR R9, FPSCR
-10aae1ee|	1	plan9	VMSR R10, FPSCR
+00100fe1|	1	plan9	MOVW APSR, R1
+fef02ce3|	1	plan9	MOVW $254, APSR
+fff42ce3|	1	plan9	MOVW $4278190080, APSR
+05f02c01|	1	plan9	MOVW.EQ R5, APSR
+09f02c11|	1	plan9	MOVW.NE R9, APSR
+109af10e|	1	plan9	MOVW.EQ FPSCR, R9
+10aaf1ee|	1	plan9	MOVW FPSCR, R10
+109ae11e|	1	plan9	MOVW.NE R9, FPSCR
+10aae1ee|	1	plan9	MOVW R10, FPSCR
 202e91e7|	1	plan9	MOVW (R1)(R0>>28), R2
 002e91e7|	1	plan9	MOVW (R1)(R0<<28), R2
 402e91e7|	1	plan9	MOVW (R1)(R0->28), R2
@@ -1200,68 +1202,110 @@
 f48259e1|	1	plan9	MOVHS -0x24(R9), R8
 f48279e1|	1	plan9	MOVHS.W -0x24(R9), R8
 f48259e0|	1	plan9	MOVHS.P -0x24(R9), R8
-002a31ee|	1	plan9	VADD.F32 S0, S2, S4
-202a31ee|	1	plan9	VADD.F32 S1, S2, S4
-802a31ee|	1	plan9	VADD.F32 S0, S3, S4
-002a71ee|	1	plan9	VADD.F32 S0, S2, S5
-035b340e|	1	plan9	VADD.EQ.F64 D3, D4, D5
-002a321e|	1	plan9	VADD.NE.F32 S0, S4, S4
-035b35ee|	1	plan9	VADD.F64 D3, D5, D5
-402a31ee|	1	plan9	VSUB.F32 S0, S2, S4
-602a31ee|	1	plan9	VSUB.F32 S1, S2, S4
-c02a31ee|	1	plan9	VSUB.F32 S0, S3, S4
-402a71ee|	1	plan9	VSUB.F32 S0, S2, S5
-435b340e|	1	plan9	VSUB.EQ.F64 D3, D4, D5
-402a321e|	1	plan9	VSUB.NE.F32 S0, S4, S4
-435b35ee|	1	plan9	VSUB.F64 D3, D5, D5
-002a21ee|	1	plan9	VMUL.F32 S0, S2, S4
-202a21ee|	1	plan9	VMUL.F32 S1, S2, S4
-802a21ee|	1	plan9	VMUL.F32 S0, S3, S4
-002a61ee|	1	plan9	VMUL.F32 S0, S2, S5
-035b240e|	1	plan9	VMUL.EQ.F64 D3, D4, D5
-002a221e|	1	plan9	VMUL.NE.F32 S0, S4, S4
-035b25ee|	1	plan9	VMUL.F64 D3, D5, D5
-002a81ee|	1	plan9	VDIV.F32 S0, S2, S4
-202a81ee|	1	plan9	VDIV.F32 S1, S2, S4
-802a81ee|	1	plan9	VDIV.F32 S0, S3, S4
-002ac1ee|	1	plan9	VDIV.F32 S0, S2, S5
-035b840e|	1	plan9	VDIV.EQ.F64 D3, D4, D5
-002a821e|	1	plan9	VDIV.NE.F32 S0, S4, S4
-035b85ee|	1	plan9	VDIV.F64 D3, D5, D5
-401ab1ee|	1	plan9	VNEG.F32 S0, S2
-601ab1ee|	1	plan9	VNEG.F32 S1, S2
-401af1ee|	1	plan9	VNEG.F32 S0, S3
-445bb1ee|	1	plan9	VNEG.F64 D4, D5
-c01ab0ee|	1	plan9	VABS.F32 S0, S2
-e01ab0ee|	1	plan9	VABS.F32 S1, S2
-c01af0ee|	1	plan9	VABS.F32 S0, S3
-c45bb0ee|	1	plan9	VABS.F64 D4, D5
-c01ab1ee|	1	plan9	VSQRT.F32 S0, S2
-e01ab1ee|	1	plan9	VSQRT.F32 S1, S2
-c01af1ee|	1	plan9	VSQRT.F32 S0, S3
-c45bb1ee|	1	plan9	VSQRT.F64 D4, D5
-c01ab7ee|	1	gnu	vcvt.f64.f32 d1, s0
-c45bb7ee|	1	gnu	vcvt.f32.f64 s10, d4
-9f9f98e1|	1	gnu	ldrex r9, [r8]
-9f9fd8e1|	1	gnu	ldrexb r9, [r8]
-9f9ff8e1|	1	gnu	ldrexh r9, [r8]
+002a310e|	1	plan9	ADDF.EQ F0, F1, F2
+202a310e|	1	plan9	ADDF.EQ S1, F1, F2
+802a31ee|	1	plan9	ADDF F0, S3, F2
+002a71ee|	1	plan9	ADDF F0, F1, S5
+035b340e|	1	plan9	ADDD.EQ F3, F4, F5
+002a321e|	1	plan9	ADDF.NE F0, F2, F2
+035b35ee|	1	plan9	ADDD F3, F5, F5
+402a31ee|	1	plan9	SUBF F0, F1, F2
+602a31ee|	1	plan9	SUBF S1, F1, F2
+c02a31ee|	1	plan9	SUBF F0, S3, F2
+402a71ee|	1	plan9	SUBF F0, F1, S5
+435b340e|	1	plan9	SUBD.EQ F3, F4, F5
+402a321e|	1	plan9	SUBF.NE F0, F2, F2
+435b35ee|	1	plan9	SUBD F3, F5, F5
+002a21ee|	1	plan9	MULF F0, F1, F2
+202a21ee|	1	plan9	MULF S1, F1, F2
+802a21ee|	1	plan9	MULF F0, S3, F2
+002a61ee|	1	plan9	MULF F0, F1, S5
+035b240e|	1	plan9	MULD.EQ F3, F4, F5
+002a221e|	1	plan9	MULF.NE F0, F2, F2
+035b25ee|	1	plan9	MULD F3, F5, F5
+402a21ee|	1	plan9	NMULF F0, F1, F2
+602a21ee|	1	plan9	NMULF S1, F1, F2
+c02a21ee|	1	plan9	NMULF F0, S3, F2
+402a61ee|	1	plan9	NMULF F0, F1, S5
+435b240e|	1	plan9	NMULD.EQ F3, F4, F5
+402a221e|	1	plan9	NMULF.NE F0, F2, F2
+435b25ee|	1	plan9	NMULD F3, F5, F5
+002a01ee|	1	plan9	MULAF F0, F1, F2
+202a01ee|	1	plan9	MULAF S1, F1, F2
+802a01ee|	1	plan9	MULAF F0, S3, F2
+002a41ee|	1	plan9	MULAF F0, F1, S5
+035b040e|	1	plan9	MULAD.EQ F3, F4, F5
+002a021e|	1	plan9	MULAF.NE F0, F2, F2
+035b05ee|	1	plan9	MULAD F3, F5, F5
+402a01ee|	1	plan9	MULSF F0, F1, F2
+602a01ee|	1	plan9	MULSF S1, F1, F2
+c02a01ee|	1	plan9	MULSF F0, S3, F2
+402a41ee|	1	plan9	MULSF F0, F1, S5
+435b040e|	1	plan9	MULSD.EQ F3, F4, F5
+402a021e|	1	plan9	MULSF.NE F0, F2, F2
+435b05ee|	1	plan9	MULSD F3, F5, F5
+002a11ee|	1	plan9	NMULSF F0, F1, F2
+202a11ee|	1	plan9	NMULSF S1, F1, F2
+802a11ee|	1	plan9	NMULSF F0, S3, F2
+002a51ee|	1	plan9	NMULSF F0, F1, S5
+035b140e|	1	plan9	NMULSD.EQ F3, F4, F5
+002a121e|	1	plan9	NMULSF.NE F0, F2, F2
+035b15ee|	1	plan9	NMULSD F3, F5, F5
+402a11ee|	1	plan9	NMULAF F0, F1, F2
+602a11ee|	1	plan9	NMULAF S1, F1, F2
+c02a11ee|	1	plan9	NMULAF F0, S3, F2
+402a51ee|	1	plan9	NMULAF F0, F1, S5
+435b140e|	1	plan9	NMULAD.EQ F3, F4, F5
+402a121e|	1	plan9	NMULAF.NE F0, F2, F2
+435b15ee|	1	plan9	NMULAD F3, F5, F5
+002a81ee|	1	plan9	DIVF F0, F1, F2
+202a81ee|	1	plan9	DIVF S1, F1, F2
+802a81ee|	1	plan9	DIVF F0, S3, F2
+002ac1ee|	1	plan9	DIVF F0, F1, S5
+035b840e|	1	plan9	DIVD.EQ F3, F4, F5
+002a821e|	1	plan9	DIVF.NE F0, F2, F2
+035b85ee|	1	plan9	DIVD F3, F5, F5
+401ab1ee|	1	plan9	NEGF F0, F1
+601ab1ee|	1	plan9	NEGF S1, F1
+401af1ee|	1	plan9	NEGF F0, S3
+445bb1ee|	1	plan9	NEGD F4, F5
+c01ab0ee|	1	plan9	ABSF F0, F1
+e01ab0ee|	1	plan9	ABSF S1, F1
+c01af0ee|	1	plan9	ABSF F0, S3
+c45bb0ee|	1	plan9	ABSD F4, F5
+c01ab1ee|	1	plan9	SQRTF F0, F1
+e01ab1ee|	1	plan9	SQRTF S1, F1
+c01af1ee|	1	plan9	SQRTF F0, S3
+c45bb1ee|	1	plan9	SQRTD F4, F5
+c01ab7ee|	1	plan9	MOVFD F0, F1
+c45bb7ee|	1	plan9	MOVDF F4, F5
+c89ab4ee|	1	plan9	CMPF F8, F9
+c45bb42e|	1	plan9	CMPD.CS F4, F5
+c07ab56e|	1	plan9	CMPF.VS $0, F7
+c06bb5ee|	1	plan9	CMPD $0, F6
+9f9f98e1|	1	plan9	LDREX (R8), R9
+9f9fd8e1|	1	plan9	LDREXB (R8), R9
+9f9ff8e1|	1	plan9	LDREXH (R8), R9
 9fcfbbe1|	1	gnu	ldrexd ip, [fp]
-935f84e1|	1	gnu	strex r5, r3, [r4]
-935fc4e1|	1	gnu	strexb r5, r3, [r4]
-935fe4e1|	1	gnu	strexh r5, r3, [r4]
+935f84e1|	1	plan9	STREX R3, (R4), R5
+935fc4e1|	1	plan9	STREXB R3, (R4), R5
+935fe4e1|	1	plan9	STREXH R3, (R4), R5
 98afa9e1|	1	gnu	strexd sl, r8, [r9]
-104b08ee|	1	gnu	vmov.32 d8[0], r4
-108b14ee|	1	gnu	vmov.32 r8, d4[0]
-445ab0ee|	1	gnu	vmov.f32 s10, s8
-467bb0ee|	1	gnu	vmov.f64 d7, d6
-c68abdee|	1	gnu	vcvt.s32.f32 s16, s12
-c68abcee|	1	gnu	vcvt.u32.f32 s16, s12
-c68bbdee|	1	gnu	vcvt.s32.f64 s16, d6
-c68bbcee|	1	gnu	vcvt.u32.f64 s16, d6
-c68ab8ee|	1	gnu	vcvt.f32.s32 s16, s12
-468ab8ee|	1	gnu	vcvt.f32.u32 s16, s12
-c68bb8ee|	1	gnu	vcvt.f64.s32 d8, s12
-468bb8ee|	1	gnu	vcvt.f64.u32 d8, s12
+104b08ee|	1	plan9	MOVW R4, F8
+108b14ee|	1	plan9	MOVW F4, R8
+104a080e|	1	plan9	MOVW.EQ R4, F8
+104a181e|	1	plan9	MOVW.NE F8, R4
+904a181e|	1	plan9	MOVW.NE S17, R4
+445ab0ee|	1	plan9	MOVF F4, F5
+467bb0ee|	1	plan9	MOVD F6, F7
+c68abdee|	1	plan9	MOVFW F6, F8
+c68abcee|	1	plan9	MOVFW.U F6, F8
+c68bbdee|	1	plan9	MOVDW F6, F8
+c68bbcee|	1	plan9	MOVDW.U F6, F8
+c68ab8ee|	1	plan9	MOVWF F6, F8
+468ab8ee|	1	plan9	MOVWF.U F6, F8
+c68bb8ee|	1	plan9	MOVWD F6, F8
+468bb8ee|	1	plan9	MOVWD.U F6, F8
 000000ea|	1	plan9	B 0x8
 feffffea|	1	plan9	B 0x0
 fcffffea|	1	plan9	B 0xfffffff8
@@ -1446,34 +1490,34 @@
 b640ade0|	1	gnu	strht r4, [sp], r6
 b31022e0|	1	gnu	strht r1, [r2], -r3
 b6402de0|	1	gnu	strht r4, [sp], -r6
-00f020e3|	1	gnu	nop
-445ab0ee|	1	gnu	vmov.f32 s10, s8
-645af0ee|	1	gnu	vmov.f32 s11, s9
-467bb0ee|	1	gnu	vmov.f64 d7, d6
-104b08ee|	1	gnu	vmov.32 d8[0], r4
-104b28ee|	1	gnu	vmov.32 d8[1], r4
-108b14ee|	1	gnu	vmov.32 r8, d4[0]
-108b34ee|	1	gnu	vmov.32 r8, d4[1]
-c68abdee|	1	gnu	vcvt.s32.f32 s16, s12
-e68afdee|	1	gnu	vcvt.s32.f32 s17, s13
-c68abcee|	1	gnu	vcvt.u32.f32 s16, s12
-e68afcee|	1	gnu	vcvt.u32.f32 s17, s13
-c68bbdee|	1	gnu	vcvt.s32.f64 s16, d6
-c68bfdee|	1	gnu	vcvt.s32.f64 s17, d6
-c68bbcee|	1	gnu	vcvt.u32.f64 s16, d6
-c68bfcee|	1	gnu	vcvt.u32.f64 s17, d6
-c68ab8ee|	1	gnu	vcvt.f32.s32 s16, s12
-e68af8ee|	1	gnu	vcvt.f32.s32 s17, s13
-468ab8ee|	1	gnu	vcvt.f32.u32 s16, s12
-668af8ee|	1	gnu	vcvt.f32.u32 s17, s13
-c68bb8ee|	1	gnu	vcvt.f64.s32 d8, s12
-e68bb8ee|	1	gnu	vcvt.f64.s32 d8, s13
-468bb8ee|	1	gnu	vcvt.f64.u32 d8, s12
-668bb8ee|	1	gnu	vcvt.f64.u32 d8, s13
-c01ab7ee|	1	gnu	vcvt.f64.f32 d1, s0
-e01ab7ee|	1	gnu	vcvt.f64.f32 d1, s1
-c45bb7ee|	1	gnu	vcvt.f32.f64 s10, d4
-c65bf7ee|	1	gnu	vcvt.f32.f64 s11, d6
+00f020e3|	1	plan9	NOP
+445ab0ee|	1	plan9	MOVF F4, F5
+645af0ee|	1	plan9	MOVF S9, S11
+467bb0ee|	1	plan9	MOVD F6, F7
+104b08ee|	1	plan9	MOVW R4, F8
+104b28ee|	1	plan9	MOVW R4, D8[1]
+108b14ee|	1	plan9	MOVW F4, R8
+108b34ee|	1	plan9	MOVW D4[1], R8
+c68abdee|	1	plan9	MOVFW F6, F8
+e68afdee|	1	plan9	MOVFW S13, S17
+c68abcee|	1	plan9	MOVFW.U F6, F8
+e68afcee|	1	plan9	MOVFW.U S13, S17
+c68bbdee|	1	plan9	MOVDW F6, F8
+c68bfdee|	1	plan9	MOVDW F6, S17
+c68bbcee|	1	plan9	MOVDW.U F6, F8
+c68bfcee|	1	plan9	MOVDW.U F6, S17
+c68ab8ee|	1	plan9	MOVWF F6, F8
+e68af8ee|	1	plan9	MOVWF S13, S17
+468ab8ee|	1	plan9	MOVWF.U F6, F8
+668af8ee|	1	plan9	MOVWF.U S13, S17
+c68bb8ee|	1	plan9	MOVWD F6, F8
+e68bb8ee|	1	plan9	MOVWD S13, F8
+468bb8ee|	1	plan9	MOVWD.U F6, F8
+668bb8ee|	1	plan9	MOVWD.U S13, F8
+c01ab7ee|	1	plan9	MOVFD F0, F1
+e01ab7ee|	1	plan9	MOVFD S1, F1
+c45bb7ee|	1	plan9	MOVDF F4, F5
+c65bf7ee|	1	plan9	MOVDF F6, S11
 102083e6|	1	gnu	pkhbt r2, r3, r0
 102283e6|	1	gnu	pkhbt r2, r3, r0, lsl #4
 502083e6|	1	gnu	pkhtb r2, r3, r0, asr #32
@@ -1525,8 +1569,8 @@
 532f34e6|	1	gnu	shsax r2, r4, r3
 332f74e6|	1	gnu	uhasx r2, r4, r3
 532f74e6|	1	gnu	uhsax r2, r4, r3
-dc51afe7|	1	gnu	sbfx r5, ip, #3, #16
-dc51efe7|	1	gnu	ubfx r5, ip, #3, #16
+dc51afe7|	1	plan9	SBFX $16, $3, R12, R5
+dc51efe7|	1	plan9	UBFX $16, $3, R12, R5
 b12f88e6|	1	gnu	sel r2, r8, r1
 000201f1|	1	gnu	setend be
 000001f1|	1	gnu	setend le
@@ -1537,18 +1581,18 @@
 1155eae6|	1	gnu	usat r5, #10, r1, lsl #10
 5155eae6|	1	gnu	usat r5, #10, r1, asr #10
 335feae6|	1	gnu	usat16 r5, #10, r3
-7788a9e6|	1	gnu	sxtab r8, r9, r7, ror #16
-778889e6|	1	gnu	sxtab16 r8, r9, r7, ror #16
-7788b9e6|	1	gnu	sxtah r8, r9, r7, ror #16
-7784afe6|	1	gnu	sxtb r8, r7, ror #8
-778c8fe6|	1	gnu	sxtb16 r8, r7, ror #24
-7780bfe6|	1	gnu	sxth r8, r7
-7788e9e6|	1	gnu	uxtab r8, r9, r7, ror #16
-7788c9e6|	1	gnu	uxtab16 r8, r9, r7, ror #16
-7788f9e6|	1	gnu	uxtah r8, r9, r7, ror #16
-7784efe6|	1	gnu	uxtb r8, r7, ror #8
-778ccfe6|	1	gnu	uxtb16 r8, r7, ror #24
-7780ffe6|	1	gnu	uxth r8, r7
+7788a9e6|	1	plan9	SXTAB R7@>$16, R9, R8
+778889e6|	1	plan9	SXTAB16 R7@>$16, R9, R8
+7788b9e6|	1	plan9	SXTAH R7@>$16, R9, R8
+7784afe6|	1	plan9	MOVBS R7@>$8, R8
+778c8fe6|	1	plan9	SXTB16 R7@>$24, R8
+7780bf16|	1	plan9	MOVHS.NE R7, R8
+7788e906|	1	plan9	UXTAB.EQ R7@>$16, R9, R8
+7788c9e6|	1	plan9	UXTAB16 R7@>$16, R9, R8
+7788f9e6|	1	plan9	UXTAH R7@>$16, R9, R8
+7784efe6|	1	plan9	MOVBU R7@>$8, R8
+778ccfe6|	1	plan9	UXTB16 R7@>$24, R8
+7780ffe6|	1	plan9	MOVHU R7, R8
 11f288e7|	1	gnu	usad8 r8, r1, r2
 112388e7|	1	gnu	usada8 r8, r1, r3, r2
 02f020e3|	1	gnu	wfe