cmd/internal/obj/ppc64: fix mtocrf, cleanup other CR ops

Fix "MOVW CRx, Rx" and "MOVFL Rx, constant", The FXM field was not
encoded correctly.

Generate mtocrf instead of mtcrf when a CRx argument is used. This
form is much faster.

Simplify several conditional statements which test if the register
argument is REG_CR or one of REG_CRx if the tested argument is known
to be matched as C_CREG. Likewise, a4 is (the From3 arg) is always
TYPE_NONE in the existing optab entries for type_ 69.

Change-Id: I3a4749b1cbfdfab6a2616586ae59e932e01dae50
Reviewed-on: https://go-review.googlesource.com/c/go/+/352789
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com>
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s
index 28ceb62..b9da48a 100644
--- a/src/cmd/asm/internal/asm/testdata/ppc64.s
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.s
@@ -751,4 +751,17 @@
 	MOVD XER, R3                    // 7c6102a6
 	MOVFL CR3, CR1                  // 4c8c0000
 
+	MOVW CR0, R1			// 7c380026
+	MOVW CR7, R1			// 7c301026
+	MOVW CR, R1			// 7c200026
+
+	MOVW R1, CR			// 7c2ff120
+	MOVFL R1, CR			// 7c2ff120
+	MOVW R1, CR2			// 7c320120
+	MOVFL R1, CR2			// 7c320120
+	MOVFL R1, $255			// 7c2ff120
+	MOVFL R1, $1			// 7c301120
+	MOVFL R1, $128			// 7c380120
+	MOVFL R1, $3			// 7c203120
+
 	RET
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index ff94fa7..0901d64 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -36,6 +36,7 @@
 	"fmt"
 	"log"
 	"math"
+	"math/bits"
 	"sort"
 )
 
@@ -3353,32 +3354,30 @@
 		o1 = AOP_RRR(o1, uint32(r), 0, 0) | (uint32(v)&0x1f)<<16 | ((uint32(v)>>5)&0x1f)<<11
 
 	case 67: /* mcrf crfD,crfS */
-		if p.From.Type != obj.TYPE_REG || p.From.Reg < REG_CR0 || REG_CR7 < p.From.Reg || p.To.Type != obj.TYPE_REG || p.To.Reg < REG_CR0 || REG_CR7 < p.To.Reg {
-			c.ctxt.Diag("illegal CR field number\n%v", p)
+		if p.From.Reg == REG_CR || p.To.Reg == REG_CR {
+			c.ctxt.Diag("CR argument must be a conditional register field (CR0-CR7)\n%v", p)
 		}
 		o1 = AOP_RRR(OP_MCRF, ((uint32(p.To.Reg) & 7) << 2), ((uint32(p.From.Reg) & 7) << 2), 0)
 
 	case 68: /* mfcr rD; mfocrf CRM,rD */
-		if p.From.Type == obj.TYPE_REG && REG_CR0 <= p.From.Reg && p.From.Reg <= REG_CR7 {
-			v := int32(1 << uint(7-(p.To.Reg&7)))                                 /* CR(n) */
-			o1 = AOP_RRR(OP_MFCR, uint32(p.To.Reg), 0, 0) | 1<<20 | uint32(v)<<12 /* new form, mfocrf */
-		} else {
-			o1 = AOP_RRR(OP_MFCR, uint32(p.To.Reg), 0, 0) /* old form, whole register */
+		o1 = AOP_RRR(OP_MFCR, uint32(p.To.Reg), 0, 0) /*  form, whole register */
+		if p.From.Reg != REG_CR {
+			v := uint32(1) << uint(7-(p.From.Reg&7)) /* CR(n) */
+			o1 |= 1<<20 | v<<12                      /* new form, mfocrf */
 		}
 
-	case 69: /* mtcrf CRM,rS */
-		var v int32
-		if p.From3Type() != obj.TYPE_NONE {
-			if p.To.Reg != 0 {
-				c.ctxt.Diag("can't use both mask and CR(n)\n%v", p)
-			}
-			v = c.regoff(p.GetFrom3()) & 0xff
-		} else {
-			if p.To.Reg == 0 {
-				v = 0xff /* CR */
-			} else {
-				v = 1 << uint(7-(p.To.Reg&7)) /* CR(n) */
-			}
+	case 69: /* mtcrf CRM,rS, mtocrf CRx,rS */
+		var v uint32
+		if p.To.Reg == REG_CR {
+			v = 0xff
+		} else if p.To.Offset != 0 { // MOVFL gpr, constant
+			v = uint32(p.To.Offset)
+		} else { // p.To.Reg == REG_CRx
+			v = 1 << uint(7-(p.To.Reg&7))
+		}
+		// Use mtocrf form if only one CR field moved.
+		if bits.OnesCount32(v) == 1 {
+			v |= 1 << 8
 		}
 
 		o1 = AOP_RRR(OP_MTCRF, uint32(p.From.Reg), 0, 0) | uint32(v)<<12