arm/armasm: rename VLDR/VSTR in plan9 syntax

Some load/store instructions are renamed in plan9 syntax, such as
LDR -> MOVW
STR -> MOVW
LDRB -> MOVBU
LDRSB -> MOVBS
STRB -> MOVB
LDRH -> MOVHU
LDRSH -> MOVSH
STRH -> MOVH

And VLDR/VSTR also need to be renamed.
VLDR.F32 -> MOVF (load from memory to single FP register)
VLDR.F64 -> MOVD (load from memory to double FP register)
VSTR.F32 -> MOVF (store single FP register to memory)
VSTR.F64 -> MOVD (store double FP register to memory)

This patch fixes this issue and adds corresponding tests.

fixes  golang/go#20897

Change-Id: I03aaad6379fa6f7c9b808d6a4795a06299fb7a18
Reviewed-on: https://go-review.googlesource.com/47360
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/arm/armasm/plan9x.go b/arm/armasm/plan9x.go
index cbae803..321b081 100644
--- a/arm/armasm/plan9x.go
+++ b/arm/armasm/plan9x.go
@@ -9,6 +9,7 @@
 	"encoding/binary"
 	"fmt"
 	"io"
+	"math"
 	"strings"
 )
 
@@ -37,7 +38,7 @@
 	op := inst.Op.String()
 
 	switch inst.Op &^ 15 {
-	case LDR_EQ, LDRB_EQ, LDRH_EQ, LDRSB_EQ, LDRSH_EQ:
+	case LDR_EQ, LDRB_EQ, LDRH_EQ, LDRSB_EQ, LDRSH_EQ, VLDR_EQ:
 		// Check for RET
 		reg, _ := inst.Args[0].(Reg)
 		mem, _ := inst.Args[1].(Mem)
@@ -48,7 +49,7 @@
 		// Check for PC-relative load.
 		if mem.Base == PC && mem.Sign == 0 && mem.Mode == AddrOffset && text != nil {
 			addr := uint32(pc) + 8 + uint32(mem.Offset)
-			buf := make([]byte, 4)
+			buf := make([]byte, 8)
 			switch inst.Op &^ 15 {
 			case LDRB_EQ, LDRSB_EQ:
 				if _, err := text.ReadAt(buf[:1], int64(addr)); err != nil {
@@ -63,7 +64,7 @@
 				args[1] = fmt.Sprintf("$%#x", binary.LittleEndian.Uint16(buf))
 
 			case LDR_EQ:
-				if _, err := text.ReadAt(buf, int64(addr)); err != nil {
+				if _, err := text.ReadAt(buf[:4], int64(addr)); err != nil {
 					break
 				}
 				x := binary.LittleEndian.Uint32(buf)
@@ -72,6 +73,22 @@
 				} else {
 					args[1] = fmt.Sprintf("$%#x", x)
 				}
+
+			case VLDR_EQ:
+				switch {
+				case strings.HasPrefix(args[0], "D"): // VLDR.F64
+					if _, err := text.ReadAt(buf, int64(addr)); err != nil {
+						break
+					}
+					args[1] = fmt.Sprintf("$%f", math.Float64frombits(binary.LittleEndian.Uint64(buf)))
+				case strings.HasPrefix(args[0], "S"): // VLDR.F32
+					if _, err := text.ReadAt(buf[:4], int64(addr)); err != nil {
+						break
+					}
+					args[1] = fmt.Sprintf("$%f", math.Float32frombits(binary.LittleEndian.Uint32(buf)))
+				default:
+					panic(fmt.Sprintf("wrong FP register: %v", inst))
+				}
 			}
 		}
 	}
@@ -79,7 +96,7 @@
 	// 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:
+	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:
@@ -133,6 +150,19 @@
 		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 STR_EQ:
 		op = "MOVW" + op[3:] + suffix
@@ -143,6 +173,20 @@
 	case STRH_EQ:
 		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]
 	}
 
 	if args != nil {
diff --git a/arm/armasm/testdata/decode.txt b/arm/armasm/testdata/decode.txt
index 24b6a93..413280c 100644
--- a/arm/armasm/testdata/decode.txt
+++ b/arm/armasm/testdata/decode.txt
@@ -1228,3 +1228,27 @@
 58f07ff5|	1	plan9	DMB $8
 49f07ff5|	1	plan9	DSB $9
 62f07ff5|	1	plan9	ISB $2
+009a94ed|	1	plan9	MOVF (R4), F9
+009ad4ed|	1	plan9	MOVF (R4), S19
+009b940d|	1	plan9	MOVD.EQ (R4), F9
+003a9a1d|	1	plan9	MOVF.NE (R10), F3
+003ada1d|	1	plan9	MOVF.NE (R10), S7
+003b9aed|	1	plan9	MOVD (R10), F3
+089a93ed|	1	plan9	MOVF 0x20(R3), F9
+089ad3ed|	1	plan9	MOVF 0x20(R3), S19
+089b940d|	1	plan9	MOVD.EQ 0x20(R4), F9
+083a1a1d|	1	plan9	MOVF.NE -0x20(R10), F3
+083a5a1d|	1	plan9	MOVF.NE -0x20(R10), S7
+083b1aed|	1	plan9	MOVD -0x20(R10), F3
+009a84ed|	1	plan9	MOVF F9, (R4)
+009ac4ed|	1	plan9	MOVF S19, (R4)
+009b840d|	1	plan9	MOVD.EQ F9, (R4)
+003a8a1d|	1	plan9	MOVF.NE F3, (R10)
+003aca1d|	1	plan9	MOVF.NE S7, (R10)
+003b8aed|	1	plan9	MOVD F3, (R10)
+089a83ed|	1	plan9	MOVF F9, 0x20(R3)
+089ac3ed|	1	plan9	MOVF S19, 0x20(R3)
+089b840d|	1	plan9	MOVD.EQ F9, 0x20(R4)
+083a0a1d|	1	plan9	MOVF.NE F3, -0x20(R10)
+083a4a1d|	1	plan9	MOVF.NE S7, -0x20(R10)
+083b0aed|	1	plan9	MOVD F3, -0x20(R10)