From 43ea3054358a3d2dde5787e088dffaba27c4d91e Mon Sep 17 00:00:00 2001
From: Yao Zhang <lunaria21@gmail.com>
Date: Thu, 10 Sep 2015 11:32:32 -0400
Subject: [PATCH] cmd/asm: added support for GOARCH=mips64{,le}

Change-Id: I951387f88993715e86b6ab9f18d38ed5c691ee0f
Reviewed-on: https://go-review.googlesource.com/14443
Reviewed-by: Minux Ma <minux@golang.org>
---
 src/cmd/asm/internal/arch/arch.go            |  63 +++
 src/cmd/asm/internal/arch/mips64.go          |  64 +++
 src/cmd/asm/internal/asm/asm.go              |  18 +
 src/cmd/asm/internal/asm/endtoend_test.go    |   4 +
 src/cmd/asm/internal/asm/operand_test.go     |  88 +++++
 src/cmd/asm/internal/asm/testdata/mips64.out |  99 +++++
 src/cmd/asm/internal/asm/testdata/mips64.s   | 392 +++++++++++++++++++
 7 files changed, 728 insertions(+)
 create mode 100644 src/cmd/asm/internal/arch/mips64.go
 create mode 100644 src/cmd/asm/internal/asm/testdata/mips64.out
 create mode 100644 src/cmd/asm/internal/asm/testdata/mips64.s

diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go
index 04622e63ec..cc1aab6ad5 100644
--- a/src/cmd/asm/internal/arch/arch.go
+++ b/src/cmd/asm/internal/arch/arch.go
@@ -8,6 +8,7 @@ import (
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 	"cmd/internal/obj/arm64"
+	"cmd/internal/obj/mips"
 	"cmd/internal/obj/ppc64"
 	"cmd/internal/obj/x86"
 	"fmt"
@@ -65,6 +66,14 @@ func Set(GOARCH string) *Arch {
 		return archArm()
 	case "arm64":
 		return archArm64()
+	case "mips64":
+		a := archMips64()
+		a.LinkArch = &mips.Linkmips64
+		return a
+	case "mips64le":
+		a := archMips64()
+		a.LinkArch = &mips.Linkmips64le
+		return a
 	case "ppc64":
 		a := archPPC64()
 		a.LinkArch = &ppc64.Linkppc64
@@ -363,3 +372,57 @@ func archPPC64() *Arch {
 		IsJump:         jumpPPC64,
 	}
 }
+
+func archMips64() *Arch {
+	register := make(map[string]int16)
+	// Create maps for easy lookup of instruction names etc.
+	// Note that there is no list of names as there is for x86.
+	for i := mips.REG_R0; i <= mips.REG_R31; i++ {
+		register[obj.Rconv(i)] = int16(i)
+	}
+	for i := mips.REG_F0; i <= mips.REG_F31; i++ {
+		register[obj.Rconv(i)] = int16(i)
+	}
+	for i := mips.REG_M0; i <= mips.REG_M31; i++ {
+		register[obj.Rconv(i)] = int16(i)
+	}
+	for i := mips.REG_FCR0; i <= mips.REG_FCR31; i++ {
+		register[obj.Rconv(i)] = int16(i)
+	}
+	register["HI"] = mips.REG_HI
+	register["LO"] = mips.REG_LO
+	// Pseudo-registers.
+	register["SB"] = RSB
+	register["FP"] = RFP
+	register["PC"] = RPC
+	// Avoid unintentionally clobbering g using R30.
+	delete(register, "R30")
+	register["g"] = mips.REG_R30
+	registerPrefix := map[string]bool{
+		"F":   true,
+		"FCR": true,
+		"M":   true,
+		"R":   true,
+	}
+
+	instructions := make(map[string]int)
+	for i, s := range obj.Anames {
+		instructions[s] = i
+	}
+	for i, s := range mips.Anames {
+		if i >= obj.A_ARCHSPECIFIC {
+			instructions[s] = i + obj.ABaseMIPS64
+		}
+	}
+	// Annoying alias.
+	instructions["JAL"] = mips.AJAL
+
+	return &Arch{
+		LinkArch:       &mips.Linkmips64,
+		Instructions:   instructions,
+		Register:       register,
+		RegisterPrefix: registerPrefix,
+		RegisterNumber: mipsRegisterNumber,
+		IsJump:         jumpMIPS64,
+	}
+}
diff --git a/src/cmd/asm/internal/arch/mips64.go b/src/cmd/asm/internal/arch/mips64.go
new file mode 100644
index 0000000000..b5867d93df
--- /dev/null
+++ b/src/cmd/asm/internal/arch/mips64.go
@@ -0,0 +1,64 @@
+// Copyright 2015 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.
+
+// This file encapsulates some of the odd characteristics of the
+// 64-bit MIPS (MIPS64) instruction set, to minimize its interaction
+// with the core of the assembler.
+
+package arch
+
+import "cmd/internal/obj/mips"
+
+func jumpMIPS64(word string) bool {
+	switch word {
+	case "BEQ", "BFPF", "BFPT", "BGEZ", "BGEZAL", "BGTZ", "BLEZ", "BLTZ", "BLTZAL", "BNE", "JMP", "JAL", "CALL":
+		return true
+	}
+	return false
+}
+
+// IsMIPS64CMP reports whether the op (as defined by an mips.A* constant) is
+// one of the CMP instructions that require special handling.
+func IsMIPS64CMP(op int) bool {
+	switch op {
+	case mips.ACMPEQF, mips.ACMPEQD, mips.ACMPGEF, mips.ACMPGED,
+		mips.ACMPGTF, mips.ACMPGTD:
+		return true
+	}
+	return false
+}
+
+// IsMIPS64MUL reports whether the op (as defined by an mips.A* constant) is
+// one of the MUL/DIV/REM instructions that require special handling.
+func IsMIPS64MUL(op int) bool {
+	switch op {
+	case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU,
+		mips.ADIV, mips.ADIVU, mips.ADIVV, mips.ADIVVU,
+		mips.AREM, mips.AREMU, mips.AREMV, mips.AREMVU:
+		return true
+	}
+	return false
+}
+
+func mipsRegisterNumber(name string, n int16) (int16, bool) {
+	switch name {
+	case "F":
+		if 0 <= n && n <= 31 {
+			return mips.REG_F0 + n, true
+		}
+	case "FCR":
+		if 0 <= n && n <= 31 {
+			return mips.REG_FCR0 + n, true
+		}
+	case "M":
+		if 0 <= n && n <= 31 {
+			return mips.REG_M0 + n, true
+		}
+	case "R":
+		if 0 <= n && n <= 31 {
+			return mips.REG_R0 + n, true
+		}
+	}
+	return 0, false
+}
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index 6128ca81e0..9da3664db1 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -373,6 +373,14 @@ func (p *Parser) asmJump(op int, cond string, a []obj.Addr) {
 			prog.Reg = reg
 			break
 		}
+		if p.arch.Thechar == '0' {
+			// 3-operand jumps.
+			// First two must be registers
+			target = &a[2]
+			prog.From = a[0]
+			prog.Reg = p.getRegister(prog, op, &a[1])
+			break
+		}
 		fallthrough
 	default:
 		p.errorf("wrong number of arguments to %s instruction", obj.Aconv(op))
@@ -509,11 +517,21 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			break
+		} else if p.arch.Thechar == '0' {
+			if arch.IsMIPS64CMP(op) || arch.IsMIPS64MUL(op) {
+				prog.From = a[0]
+				prog.Reg = p.getRegister(prog, op, &a[1])
+				break
+			}
 		}
 		prog.From = a[0]
 		prog.To = a[1]
 	case 3:
 		switch p.arch.Thechar {
+		case '0':
+			prog.From = a[0]
+			prog.Reg = p.getRegister(prog, op, &a[1])
+			prog.To = a[2]
 		case '5':
 			// Special cases.
 			if arch.IsARMSTREX(op) {
diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go
index abe4e4efbc..6e339ad0b5 100644
--- a/src/cmd/asm/internal/asm/endtoend_test.go
+++ b/src/cmd/asm/internal/asm/endtoend_test.go
@@ -89,3 +89,7 @@ func TestAMD64EndToEnd(t *testing.T) {
 func Test386EndToEnd(t *testing.T) {
 	testEndToEnd(t, "386")
 }
+
+func TestMIPS64EndToEnd(t *testing.T) {
+	testEndToEnd(t, "mips64")
+}
diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go
index 0f8271b5f8..ecf52c5620 100644
--- a/src/cmd/asm/internal/asm/operand_test.go
+++ b/src/cmd/asm/internal/asm/operand_test.go
@@ -65,6 +65,11 @@ func TestPPC64OperandParser(t *testing.T) {
 	testOperandParser(t, parser, ppc64OperandTests)
 }
 
+func TestMIPS64OperandParser(t *testing.T) {
+	parser := newParser("mips64")
+	testOperandParser(t, parser, mips64OperandTests)
+}
+
 type operandTest struct {
 	input, output string
 }
@@ -435,3 +440,86 @@ var arm64OperandTests = []operandTest{
 	{"(R29, RSP)", "(R29, RSP)"},
 	{"[):[o-FP", ""}, // Issue 12469 - asm hung parsing the o-FP range on non ARM platforms.
 }
+
+var mips64OperandTests = []operandTest{
+	{"$((1<<63)-1)", "$9223372036854775807"},
+	{"$(-64*1024)", "$-65536"},
+	{"$(1024 * 8)", "$8192"},
+	{"$-1", "$-1"},
+	{"$-24(R4)", "$-24(R4)"},
+	{"$0", "$0"},
+	{"$0(R1)", "$(R1)"},
+	{"$0.5", "$(0.5)"},
+	{"$0x7000", "$28672"},
+	{"$0x88888eef", "$2290650863"},
+	{"$1", "$1"},
+	{"$_main<>(SB)", "$_main<>(SB)"},
+	{"$argframe(FP)", "$argframe(FP)"},
+	{"$~3", "$-4"},
+	{"(-288-3*8)(R1)", "-312(R1)"},
+	{"(16)(R7)", "16(R7)"},
+	{"(8)(g)", "8(g)"},
+	{"(R0)", "(R0)"},
+	{"(R3)", "(R3)"},
+	{"(R4)", "(R4)"},
+	{"(R5)", "(R5)"},
+	{"-1(R4)", "-1(R4)"},
+	{"-1(R5)", "-1(R5)"},
+	{"6(PC)", "6(PC)"},
+	{"F14", "F14"},
+	{"F15", "F15"},
+	{"F16", "F16"},
+	{"F17", "F17"},
+	{"F18", "F18"},
+	{"F19", "F19"},
+	{"F20", "F20"},
+	{"F21", "F21"},
+	{"F22", "F22"},
+	{"F23", "F23"},
+	{"F24", "F24"},
+	{"F25", "F25"},
+	{"F26", "F26"},
+	{"F27", "F27"},
+	{"F28", "F28"},
+	{"F29", "F29"},
+	{"F30", "F30"},
+	{"F31", "F31"},
+	{"R0", "R0"},
+	{"R1", "R1"},
+	{"R11", "R11"},
+	{"R12", "R12"},
+	{"R13", "R13"},
+	{"R14", "R14"},
+	{"R15", "R15"},
+	{"R16", "R16"},
+	{"R17", "R17"},
+	{"R18", "R18"},
+	{"R19", "R19"},
+	{"R2", "R2"},
+	{"R20", "R20"},
+	{"R21", "R21"},
+	{"R22", "R22"},
+	{"R23", "R23"},
+	{"R24", "R24"},
+	{"R25", "R25"},
+	{"R26", "R26"},
+	{"R27", "R27"},
+	{"R28", "R28"},
+	{"R29", "R29"},
+	{"R3", "R3"},
+	{"R31", "R31"},
+	{"R4", "R4"},
+	{"R5", "R5"},
+	{"R6", "R6"},
+	{"R7", "R7"},
+	{"R8", "R8"},
+	{"R9", "R9"},
+	{"LO", "LO"},
+	{"a(FP)", "a(FP)"},
+	{"g", "g"},
+	{"ret+8(FP)", "ret+8(FP)"},
+	{"runtime路abort(SB)", "runtime.abort(SB)"},
+	{"路AddUint32(SB)", "\"\".AddUint32(SB)"},
+	{"路trunc(SB)", "\"\".trunc(SB)"},
+	{"[):[o-FP", ""}, // Issue 12469 - asm hung parsing the o-FP range on non ARM platforms.
+}
diff --git a/src/cmd/asm/internal/asm/testdata/mips64.out b/src/cmd/asm/internal/asm/testdata/mips64.out
new file mode 100644
index 0000000000..9263a7ba4b
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/mips64.out
@@ -0,0 +1,99 @@
+8 00001 (testdata/mips64.s:8)	TEXT	foo(SB), 0, $0
+18 00002 (testdata/mips64.s:18)	MOVW	R1, R2
+19 00003 (testdata/mips64.s:19)	MOVW	LO, R1
+20 00004 (testdata/mips64.s:20)	MOVW	HI, R1
+21 00005 (testdata/mips64.s:21)	MOVW	R1, LO
+22 00006 (testdata/mips64.s:22)	MOVW	R1, HI
+23 00007 (testdata/mips64.s:23)	MOVV	R1, R2
+24 00008 (testdata/mips64.s:24)	MOVV	LO, R1
+25 00009 (testdata/mips64.s:25)	MOVV	HI, R1
+26 00010 (testdata/mips64.s:26)	MOVV	R1, LO
+27 00011 (testdata/mips64.s:27)	MOVV	R1, HI
+33 00012 (testdata/mips64.s:33)	MOVW	foo<>+3(SB), R2
+34 00013 (testdata/mips64.s:34)	MOVW	16(R1), R2
+35 00014 (testdata/mips64.s:35)	MOVW	(R1), R2
+36 00015 (testdata/mips64.s:36)	MOVV	foo<>+3(SB), R2
+37 00016 (testdata/mips64.s:37)	MOVV	16(R1), R2
+38 00017 (testdata/mips64.s:38)	MOVV	(R1), R2
+44 00018 (testdata/mips64.s:44)	MOVB	R1, R2
+50 00019 (testdata/mips64.s:50)	MOVB	foo<>+3(SB), R2
+51 00020 (testdata/mips64.s:51)	MOVB	16(R1), R2
+52 00021 (testdata/mips64.s:52)	MOVB	(R1), R2
+61 00022 (testdata/mips64.s:61)	MOVD	foo<>+3(SB), F2
+62 00023 (testdata/mips64.s:62)	MOVD	16(R1), F2
+63 00024 (testdata/mips64.s:63)	MOVD	(R1), F2
+69 00025 (testdata/mips64.s:69)	MOVD	$(0.10000000000000001), F2
+75 00026 (testdata/mips64.s:75)	MOVD	F1, F2
+81 00027 (testdata/mips64.s:81)	MOVD	F2, foo<>+3(SB)
+82 00028 (testdata/mips64.s:82)	MOVD	F2, 16(R1)
+83 00029 (testdata/mips64.s:83)	MOVD	F2, (R1)
+92 00030 (testdata/mips64.s:92)	MOVW	R1, foo<>+3(SB)
+93 00031 (testdata/mips64.s:93)	MOVW	R1, 16(R2)
+94 00032 (testdata/mips64.s:94)	MOVW	R1, (R2)
+95 00033 (testdata/mips64.s:95)	MOVV	R1, foo<>+3(SB)
+96 00034 (testdata/mips64.s:96)	MOVV	R1, 16(R2)
+97 00035 (testdata/mips64.s:97)	MOVV	R1, (R2)
+103 00036 (testdata/mips64.s:103)	MOVB	R1, foo<>+3(SB)
+104 00037 (testdata/mips64.s:104)	MOVB	R1, 16(R2)
+105 00038 (testdata/mips64.s:105)	MOVB	R1, (R2)
+114 00039 (testdata/mips64.s:114)	MOVD	F1, foo<>+3(SB)
+115 00040 (testdata/mips64.s:115)	MOVD	F1, 16(R2)
+116 00041 (testdata/mips64.s:116)	MOVD	F1, (R2)
+125 00042 (testdata/mips64.s:125)	MOVW	FCR0, R1
+131 00043 (testdata/mips64.s:131)	MOVW	R1, FCR0
+137 00044 (testdata/mips64.s:137)	MOVW	R1, M1
+138 00045 (testdata/mips64.s:138)	MOVV	R1, M1
+144 00046 (testdata/mips64.s:144)	MOVW	M1, R1
+145 00047 (testdata/mips64.s:145)	MOVV	M1, R1
+158 00048 (testdata/mips64.s:158)	ADD	R1, R2, R3
+164 00049 (testdata/mips64.s:164)	ADD	$1, R2, R3
+170 00050 (testdata/mips64.s:170)	ADD	R1, R2
+176 00051 (testdata/mips64.s:176)	ADD	$4, R1
+182 00052 (testdata/mips64.s:182)	MUL	R1, R2
+188 00053 (testdata/mips64.s:188)	SLL	R1, R2, R3
+194 00054 (testdata/mips64.s:194)	SLL	R1, R2
+200 00055 (testdata/mips64.s:200)	SLL	$4, R1, R2
+206 00056 (testdata/mips64.s:206)	SLL	$4, R1
+215 00057 (testdata/mips64.s:215)	MOVW	$1, R1
+216 00058 (testdata/mips64.s:216)	MOVV	$1, R1
+222 00059 (testdata/mips64.s:222)	MOVW	$1, R1
+223 00060 (testdata/mips64.s:223)	MOVW	$foo(SB), R1
+224 00061 (testdata/mips64.s:224)	MOVV	$1, R1
+225 00062 (testdata/mips64.s:225)	MOVV	$foo(SB), R1
+236 00063 (testdata/mips64.s:236)	JMP	64(PC)
+237 00064 (testdata/mips64.s:237)	JMP	63
+238 00065 (testdata/mips64.s:238)	CALL	66(PC)
+239 00066 (testdata/mips64.s:239)	CALL	63
+245 00067 (testdata/mips64.s:245)	JMP	4(R1)
+246 00068 (testdata/mips64.s:246)	JMP	foo(SB)
+247 00069 (testdata/mips64.s:247)	CALL	4(R1)
+248 00070 (testdata/mips64.s:248)	CALL	foo(SB)
+258 00071 (testdata/mips64.s:258)	BEQ	R1, 72(PC)
+259 00072 (testdata/mips64.s:259)	BEQ	R1, 71
+266 00073 (testdata/mips64.s:266)	BEQ	R1, R2, 74(PC)
+267 00074 (testdata/mips64.s:267)	BEQ	R1, R2, 73
+277 00075 (testdata/mips64.s:277)	BLTZ	R1, 76(PC)
+278 00076 (testdata/mips64.s:278)	BLTZ	R1, 75
+285 00077 (testdata/mips64.s:285)	BFPT	78(PC)
+286 00078 (testdata/mips64.s:286)	BFPT	77
+296 00079 (testdata/mips64.s:296)	ABSD	F1, F2
+302 00080 (testdata/mips64.s:302)	ADDD	F1, F2
+308 00081 (testdata/mips64.s:308)	ADDD	F1, F2, F3
+314 00082 (testdata/mips64.s:314)	CMPEQD	F1, F2
+320 00083 (testdata/mips64.s:320)	WORD	$1
+321 00084 (testdata/mips64.s:321)	WORD	$foo(SB)
+330 00085 (testdata/mips64.s:330)	NOP
+336 00086 (testdata/mips64.s:336)	NOP	R2
+342 00087 (testdata/mips64.s:342)	NOP	F2
+348 00088 (testdata/mips64.s:348)	NOP	R2
+354 00089 (testdata/mips64.s:354)	NOP	F2
+360 00090 (testdata/mips64.s:360)	NOP	$4
+365 00091 (testdata/mips64.s:365)	SYSCALL
+366 00092 (testdata/mips64.s:366)	BREAK
+367 00093 (testdata/mips64.s:367)	BREAK	$1, (R1)
+376 00094 (testdata/mips64.s:376)	SYSCALL
+377 00095 (testdata/mips64.s:377)	RET
+382 00096 (testdata/mips64.s:382)	CALL	foo(SB)
+383 00097 (testdata/mips64.s:383)	JMP	foo(SB)
+384 00098 (testdata/mips64.s:384)	CALL	foo(SB)
+392 00099 (testdata/mips64.s:392)	END
diff --git a/src/cmd/asm/internal/asm/testdata/mips64.s b/src/cmd/asm/internal/asm/testdata/mips64.s
new file mode 100644
index 0000000000..4112b4b120
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/mips64.s
@@ -0,0 +1,392 @@
+// Copyright 2015 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.
+
+// This input was created by taking the ppc64 testcase and modified
+// by hand.
+
+TEXT foo(SB),0,$0
+
+//inst:
+//
+// load ints and bytes
+//
+//	LMOVW rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	R1, R2
+	MOVW	LO, R1
+	MOVW	HI, R1
+	MOVW	R1, LO
+	MOVW	R1, HI
+	MOVV	R1, R2
+	MOVV	LO, R1
+	MOVV	HI, R1
+	MOVV	R1, LO
+	MOVV	R1, HI
+
+//	LMOVW addr ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	foo<>+3(SB), R2
+	MOVW	16(R1), R2
+	MOVW	(R1), R2
+	MOVV	foo<>+3(SB), R2
+	MOVV	16(R1), R2
+	MOVV	(R1), R2
+
+//	LMOVB rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVB	R1, R2
+
+//	LMOVB addr ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVB	foo<>+3(SB), R2
+	MOVB	16(R1), R2
+	MOVB	(R1), R2
+
+//
+// load floats
+//
+//	LFMOV addr ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVD	foo<>+3(SB), F2
+	MOVD	16(R1), F2
+	MOVD	(R1), F2
+
+//	LFMOV fimm ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVD	$0.1, F2
+
+//	LFMOV freg ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVD	F1, F2
+
+//	LFMOV freg ',' addr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVD	F2, foo<>+3(SB)
+	MOVD	F2, 16(R1)
+	MOVD	F2, (R1)
+
+//
+// store ints and bytes
+//
+//	LMOVW rreg ',' addr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	R1, foo<>+3(SB)
+	MOVW	R1, 16(R2)
+	MOVW	R1, (R2)
+	MOVV	R1, foo<>+3(SB)
+	MOVV	R1, 16(R2)
+	MOVV	R1, (R2)
+
+//	LMOVB rreg ',' addr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVB	R1, foo<>+3(SB)
+	MOVB	R1, 16(R2)
+	MOVB	R1, (R2)
+
+//
+// store floats
+//
+//	LMOVW freg ',' addr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVD	F1, foo<>+3(SB)
+	MOVD	F1, 16(R2)
+	MOVD	F1, (R2)
+
+//
+// floating point status
+//
+//	LMOVW fpscr ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	FCR0, R1
+
+//	LMOVW freg ','  fpscr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	R1, FCR0
+
+//	LMOVW rreg ',' mreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	R1, M1
+	MOVV	R1, M1
+
+//	LMOVW mreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	M1, R1
+	MOVV	M1, R1
+
+
+//
+// integer operations
+// logical instructions
+// shift instructions
+// unary instructions
+//
+//	LADDW rreg ',' sreg ',' rreg
+//	{
+//		outcode(int($1), &$2, int($4), &$6);
+//	}
+	ADD	R1, R2, R3
+
+//	LADDW imm ',' sreg ',' rreg
+//	{
+//		outcode(int($1), &$2, int($4), &$6);
+//	}
+	ADD	$1, R2, R3
+
+//	LADDW rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	ADD	R1, R2
+
+//	LADDW imm ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	ADD	$4, R1
+
+//	LMUL rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MUL	R1, R2
+
+//	LSHW rreg ',' sreg ',' rreg
+//	{
+//		outcode(int($1), &$2, int($4), &$6);
+//	}
+	SLL	R1, R2, R3
+
+//	LSHW rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	SLL	R1, R2
+
+//	LSHW imm ',' sreg ',' rreg
+//	{
+//		outcode(int($1), &$2, int($4), &$6);
+//	}
+	SLL	$4, R1, R2
+
+//	LSHW imm ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	SLL	$4, R1
+
+//
+// move immediate: macro for lui+or, addi, addis, and other combinations
+//
+//	LMOVW imm ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	$1, R1
+	MOVV	$1, R1
+
+//	LMOVW ximm ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	$1, R1
+	MOVW	$foo(SB), R1
+	MOVV	$1, R1
+	MOVV	$foo(SB), R1
+
+
+//
+// branch
+//
+//	LBRA rel
+//	{
+//		outcode(int($1), &nullgen, 0, &$2);
+//	}
+label0:
+	JMP	1(PC)
+	JMP	label0+0
+	JAL	1(PC)
+	JAL	label0+0
+
+//	LBRA addr
+//	{
+//		outcode(int($1), &nullgen, 0, &$2);
+//	}
+	JMP	4(R1)
+	JMP	foo+0(SB)
+	JAL	4(R1)
+	JAL	foo+0(SB)
+
+//
+// BEQ/BNE
+//
+//	LBRA rreg ',' rel
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+label1:
+	BEQ	R1, 1(PC)
+	BEQ	R1, label1
+
+//	LBRA rreg ',' sreg ',' rel
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+label2:
+	BEQ	R1, R2, 1(PC)
+	BEQ	R1, R2, label2
+
+//
+// other integer conditional branch
+//
+//	LBRA rreg ',' rel
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+label3:
+	BLTZ	R1, 1(PC)
+	BLTZ	R1, label3
+
+//
+// floating point conditional branch
+//
+//	LBRA rel
+label4:
+	BFPT	1(PC)
+	BFPT	label4
+
+
+//
+// floating point operate
+//
+//	LFCONV freg ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	ABSD	F1, F2
+
+//	LFADD freg ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	ADDD	F1, F2
+
+//	LFADD freg ',' freg ',' freg
+//	{
+//		outcode(int($1), &$2, int($4.Reg), &$6);
+//	}
+	ADDD	F1, F2, F3
+
+//	LFCMP freg ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	CMPEQD	F1, F2
+
+
+//
+// WORD
+//
+	WORD	$1
+	WORD	$foo(SB)
+
+//
+// NOP
+//
+//	LNOP comma // asm doesn't support the trailing comma.
+//	{
+//		outcode(int($1), &nullgen, 0, &nullgen);
+//	}
+	NOP
+
+//	LNOP rreg comma // asm doesn't support the trailing comma.
+//	{
+//		outcode(int($1), &$2, 0, &nullgen);
+//	}
+	NOP R2
+
+//	LNOP freg comma // asm doesn't support the trailing comma.
+//	{
+//		outcode(int($1), &$2, 0, &nullgen);
+//	}
+	NOP	F2
+
+//	LNOP ',' rreg // asm doesn't support the leading comma.
+//	{
+//		outcode(int($1), &nullgen, 0, &$3);
+//	}
+	NOP	R2
+
+//	LNOP ',' freg // asm doesn't support the leading comma.
+//	{
+//		outcode(int($1), &nullgen, 0, &$3);
+//	}
+	NOP	F2
+
+//	LNOP imm
+//	{
+//		outcode(int($1), &$2, 0, &nullgen);
+//	}
+	NOP	$4
+
+//
+// special
+//
+	SYSCALL
+	BREAK
+	BREAK	$1, (R1) // overloaded CACHE opcode
+
+//
+// RET
+//
+//	LRETRN	comma // asm doesn't support the trailing comma.
+//	{
+//		outcode(int($1), &nullgen, 0, &nullgen);
+//	}
+	SYSCALL
+	RET
+
+
+// More JMP/JAL cases, and canonical names JMP, CALL.
+
+	JAL	foo(SB)
+	JMP	foo(SB)
+	CALL	foo(SB)
+
+// END
+//
+//	LEND	comma // asm doesn't support the trailing comma.
+//	{
+//		outcode(int($1), &nullgen, 0, &nullgen);
+//	}
+	END
-- 
2.30.9