// cmd/9l/optab.c, cmd/9l/asmout.c from Vita Nuova.
//
//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
//	Portions Copyright © 1997-1999 Vita Nuova Limited
//	Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
//	Portions Copyright © 2004,2006 Bruce Ellis
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
//	Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
//	Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package ppc64

import (
	"cmd/internal/obj"
	"cmd/internal/objabi"
	"encoding/binary"
	"fmt"
	"internal/buildcfg"
	"log"
	"math"
	"math/bits"
	"sort"
)

// ctxt9 holds state while assembling a single function.
// Each function gets a fresh ctxt9.
// This allows for multiple functions to be safely concurrently assembled.
type ctxt9 struct {
	ctxt       *obj.Link
	newprog    obj.ProgAlloc
	cursym     *obj.LSym
	autosize   int32
	instoffset int64
	pc         int64
}

// Instruction layout.

const (
	r0iszero = 1
)

const (
	// R bit option in prefixed load/store/add D-form operations
	PFX_R_ABS   = 0 // Offset is absolute
	PFX_R_PCREL = 1 // Offset is relative to PC, RA should be 0
)

const (
	// The preferred hardware nop instruction.
	NOP = 0x60000000
)

type Optab struct {
	as    obj.As // Opcode
	a1    uint8  // p.From argument (obj.Addr). p is of type obj.Prog.
	a2    uint8  // p.Reg argument (int16 Register)
	a3    uint8  // p.RestArgs[0]  (obj.AddrPos)
	a4    uint8  // p.RestArgs[1]
	a5    uint8  // p.RestARgs[2]
	a6    uint8  // p.To (obj.Addr)
	type_ int8   // cases in asmout below. E.g., 44 = st r,(ra+rb); 45 = ld (ra+rb), r
	size  int8   // Text space in bytes to lay operation

	// A prefixed instruction is generated by this opcode. This cannot be placed
	// across a 64B PC address. Opcodes should not translate to more than one
	// prefixed instruction. The prefixed instruction should be written first
	// (e.g when Optab.size > 8).
	ispfx bool

	asmout func(*ctxt9, *obj.Prog, *Optab, *[5]uint32)
}

// optab contains an array to be sliced of accepted operand combinations for an
// instruction. Unused arguments and fields are not explicitly enumerated, and
// should not be listed for clarity. Unused arguments and values should always
// assume the default value for the given type.
//
// optab does not list every valid ppc64 opcode, it enumerates representative
// operand combinations for a class of instruction.  The variable oprange indexes
// all valid ppc64 opcodes.
//
// oprange is initialized to point a slice within optab which contains the valid
// operand combinations for a given instruction.  This is initialized from buildop.
//
// Likewise, each slice of optab is dynamically sorted using the ocmp Sort interface
// to arrange entries to minimize text size of each opcode.
//
// optab is the sorted result of combining optabBase, optabGen, and prefixableOptab.
var optab []Optab

var optabBase = []Optab{
	{as: obj.ATEXT, a1: C_LOREG, a6: C_TEXTSIZE, type_: 0, size: 0},
	{as: obj.ATEXT, a1: C_LOREG, a3: C_32CON, a6: C_TEXTSIZE, type_: 0, size: 0},
	{as: obj.ATEXT, a1: C_ADDR, a6: C_TEXTSIZE, type_: 0, size: 0},
	{as: obj.ATEXT, a1: C_ADDR, a3: C_32CON, a6: C_TEXTSIZE, type_: 0, size: 0},
	/* move register */
	{as: AADD, a1: C_REG, a2: C_REG, a6: C_REG, type_: 2, size: 4},
	{as: AADD, a1: C_REG, a6: C_REG, type_: 2, size: 4},
	{as: AADD, a1: C_S16CON, a2: C_REG, a6: C_REG, type_: 4, size: 4},
	{as: AADD, a1: C_S16CON, a6: C_REG, type_: 4, size: 4},
	{as: AADD, a1: C_U16CON, a2: C_REG, a6: C_REG, type_: 22, size: 8},
	{as: AADD, a1: C_U16CON, a6: C_REG, type_: 22, size: 8},
	{as: AADDIS, a1: C_S16CON, a2: C_REG, a6: C_REG, type_: 20, size: 4},
	{as: AADDIS, a1: C_S16CON, a6: C_REG, type_: 20, size: 4},
	{as: AADDC, a1: C_REG, a2: C_REG, a6: C_REG, type_: 2, size: 4},
	{as: AADDC, a1: C_REG, a6: C_REG, type_: 2, size: 4},
	{as: AADDC, a1: C_S16CON, a2: C_REG, a6: C_REG, type_: 4, size: 4},
	{as: AADDC, a1: C_S16CON, a6: C_REG, type_: 4, size: 4},
	{as: AADDC, a1: C_32CON, a2: C_REG, a6: C_REG, type_: 22, size: 12},
	{as: AADDC, a1: C_32CON, a6: C_REG, type_: 22, size: 12},
	{as: AAND, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4}, /* logical, no literal */
	{as: AAND, a1: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: AANDCC, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: AANDCC, a1: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: AANDCC, a1: C_U16CON, a6: C_REG, type_: 58, size: 4},
	{as: AANDCC, a1: C_U16CON, a2: C_REG, a6: C_REG, type_: 58, size: 4},
	{as: AANDCC, a1: C_S16CON, a6: C_REG, type_: 23, size: 8},
	{as: AANDCC, a1: C_S16CON, a2: C_REG, a6: C_REG, type_: 23, size: 8},
	{as: AANDCC, a1: C_32CON, a6: C_REG, type_: 23, size: 12},
	{as: AANDCC, a1: C_32CON, a2: C_REG, a6: C_REG, type_: 23, size: 12},
	{as: AANDISCC, a1: C_U16CON, a6: C_REG, type_: 58, size: 4},
	{as: AANDISCC, a1: C_U16CON, a2: C_REG, a6: C_REG, type_: 58, size: 4},
	{as: AMULLW, a1: C_REG, a2: C_REG, a6: C_REG, type_: 2, size: 4},
	{as: AMULLW, a1: C_REG, a6: C_REG, type_: 2, size: 4},
	{as: AMULLW, a1: C_S16CON, a2: C_REG, a6: C_REG, type_: 4, size: 4},
	{as: AMULLW, a1: C_S16CON, a6: C_REG, type_: 4, size: 4},
	{as: AMULLW, a1: C_32CON, a2: C_REG, a6: C_REG, type_: 22, size: 12},
	{as: AMULLW, a1: C_32CON, a6: C_REG, type_: 22, size: 12},
	{as: ASUBC, a1: C_REG, a2: C_REG, a6: C_REG, type_: 10, size: 4},
	{as: ASUBC, a1: C_REG, a6: C_REG, type_: 10, size: 4},
	{as: ASUBC, a1: C_REG, a3: C_S16CON, a6: C_REG, type_: 27, size: 4},
	{as: ASUBC, a1: C_REG, a3: C_32CON, a6: C_REG, type_: 28, size: 12},
	{as: AOR, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4}, /* logical, literal not cc (or/xor) */
	{as: AOR, a1: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: AOR, a1: C_U16CON, a6: C_REG, type_: 58, size: 4},
	{as: AOR, a1: C_U16CON, a2: C_REG, a6: C_REG, type_: 58, size: 4},
	{as: AOR, a1: C_S16CON, a6: C_REG, type_: 23, size: 8},
	{as: AOR, a1: C_S16CON, a2: C_REG, a6: C_REG, type_: 23, size: 8},
	{as: AOR, a1: C_U32CON, a2: C_REG, a6: C_REG, type_: 21, size: 8},
	{as: AOR, a1: C_U32CON, a6: C_REG, type_: 21, size: 8},
	{as: AOR, a1: C_32CON, a6: C_REG, type_: 23, size: 12},
	{as: AOR, a1: C_32CON, a2: C_REG, a6: C_REG, type_: 23, size: 12},
	{as: AORIS, a1: C_U16CON, a6: C_REG, type_: 58, size: 4},
	{as: AORIS, a1: C_U16CON, a2: C_REG, a6: C_REG, type_: 58, size: 4},
	{as: ADIVW, a1: C_REG, a2: C_REG, a6: C_REG, type_: 2, size: 4}, /* op r1[,r2],r3 */
	{as: ADIVW, a1: C_REG, a6: C_REG, type_: 2, size: 4},
	{as: ASUB, a1: C_REG, a2: C_REG, a6: C_REG, type_: 10, size: 4}, /* op r2[,r1],r3 */
	{as: ASUB, a1: C_REG, a6: C_REG, type_: 10, size: 4},
	{as: ASLW, a1: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: ASLW, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: ASLD, a1: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: ASLD, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: ASLD, a1: C_U15CON, a2: C_REG, a6: C_REG, type_: 25, size: 4},
	{as: ASLD, a1: C_U15CON, a6: C_REG, type_: 25, size: 4},
	{as: AEXTSWSLI, a1: C_U15CON, a6: C_REG, type_: 25, size: 4},
	{as: AEXTSWSLI, a1: C_U15CON, a2: C_REG, a6: C_REG, type_: 25, size: 4},
	{as: ASLW, a1: C_U15CON, a2: C_REG, a6: C_REG, type_: 57, size: 4},
	{as: ASLW, a1: C_U15CON, a6: C_REG, type_: 57, size: 4},
	{as: ASRAW, a1: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: ASRAW, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: ASRAW, a1: C_U15CON, a2: C_REG, a6: C_REG, type_: 56, size: 4},
	{as: ASRAW, a1: C_U15CON, a6: C_REG, type_: 56, size: 4},
	{as: ASRAD, a1: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: ASRAD, a1: C_REG, a2: C_REG, a6: C_REG, type_: 6, size: 4},
	{as: ASRAD, a1: C_U15CON, a2: C_REG, a6: C_REG, type_: 56, size: 4},
	{as: ASRAD, a1: C_U15CON, a6: C_REG, type_: 56, size: 4},
	{as: ARLWNM, a1: C_U15CON, a2: C_REG, a3: C_32CON, a6: C_REG, type_: 63, size: 4},
	{as: ARLWNM, a1: C_U15CON, a2: C_REG, a3: C_U15CON, a4: C_U15CON, a6: C_REG, type_: 63, size: 4},
	{as: ARLWNM, a1: C_REG, a2: C_REG, a3: C_32CON, a6: C_REG, type_: 63, size: 4},
	{as: ARLWNM, a1: C_REG, a2: C_REG, a3: C_U15CON, a4: C_U15CON, a6: C_REG, type_: 63, size: 4},
	{as: ACLRLSLWI, a1: C_U15CON, a2: C_REG, a3: C_32CON, a6: C_REG, type_: 62, size: 4},
	{as: ARLDMI, a1: C_U15CON, a2: C_REG, a3: C_32CON, a6: C_REG, type_: 30, size: 4},
	{as: ARLDC, a1: C_U15CON, a2: C_REG, a3: C_32CON, a6: C_REG, type_: 29, size: 4},
	{as: ARLDC, a1: C_REG, a3: C_U8CON, a4: C_U8CON, a6: C_REG, type_: 9, size: 4},
	{as: ARLDCL, a1: C_U15CON, a2: C_REG, a3: C_32CON, a6: C_REG, type_: 29, size: 4},
	{as: ARLDCL, a1: C_REG, a2: C_REG, a3: C_32CON, a6: C_REG, type_: 14, size: 4},
	{as: ARLDICL, a1: C_REG, a2: C_REG, a3: C_32CON, a6: C_REG, type_: 14, size: 4},
	{as: ARLDICL, a1: C_U15CON, a2: C_REG, a3: C_32CON, a6: C_REG, type_: 14, size: 4},
	{as: ARLDCL, a1: C_REG, a3: C_32CON, a6: C_REG, type_: 14, size: 4},
	{as: AFADD, a1: C_FREG, a6: C_FREG, type_: 2, size: 4},
	{as: AFADD, a1: C_FREG, a2: C_FREG, a6: C_FREG, type_: 2, size: 4},
	{as: ADADDQ, a1: C_FREGP, a6: C_FREGP, type_: 2, size: 4},
	{as: ADADDQ, a1: C_FREGP, a2: C_FREGP, a6: C_FREGP, type_: 2, size: 4},
	{as: AFABS, a1: C_FREG, a6: C_FREG, type_: 33, size: 4},
	{as: AFABS, a6: C_FREG, type_: 33, size: 4},
	{as: AFMADD, a1: C_FREG, a2: C_FREG, a3: C_FREG, a6: C_FREG, type_: 34, size: 4},
	{as: AFMUL, a1: C_FREG, a6: C_FREG, type_: 32, size: 4},
	{as: AFMUL, a1: C_FREG, a2: C_FREG, a6: C_FREG, type_: 32, size: 4},
	{as: ADMULQ, a1: C_FREGP, a6: C_FREGP, type_: 32, size: 4},
	{as: ADMULQ, a1: C_FREGP, a2: C_FREGP, a6: C_FREGP, type_: 32, size: 4},

	{as: AMOVBU, a1: C_REG, a6: C_SOREG, type_: 7, size: 4},
	{as: AMOVBU, a1: C_REG, a6: C_XOREG, type_: 108, size: 4},
	{as: AMOVBU, a1: C_SOREG, a6: C_REG, type_: 8, size: 8},
	{as: AMOVBU, a1: C_XOREG, a6: C_REG, type_: 109, size: 8},

	{as: AMOVBZU, a1: C_REG, a6: C_SOREG, type_: 7, size: 4},
	{as: AMOVBZU, a1: C_REG, a6: C_XOREG, type_: 108, size: 4},
	{as: AMOVBZU, a1: C_SOREG, a6: C_REG, type_: 8, size: 4},
	{as: AMOVBZU, a1: C_XOREG, a6: C_REG, type_: 109, size: 4},

	{as: AMOVHBR, a1: C_REG, a6: C_XOREG, type_: 44, size: 4},
	{as: AMOVHBR, a1: C_XOREG, a6: C_REG, type_: 45, size: 4},

	{as: AMOVB, a1: C_SOREG, a6: C_REG, type_: 8, size: 8},
	{as: AMOVB, a1: C_XOREG, a6: C_REG, type_: 109, size: 8},
	{as: AMOVB, a1: C_REG, a6: C_SOREG, type_: 7, size: 4},
	{as: AMOVB, a1: C_REG, a6: C_XOREG, type_: 108, size: 4},
	{as: AMOVB, a1: C_REG, a6: C_REG, type_: 13, size: 4},

	{as: AMOVBZ, a1: C_SOREG, a6: C_REG, type_: 8, size: 4},
	{as: AMOVBZ, a1: C_XOREG, a6: C_REG, type_: 109, size: 4},
	{as: AMOVBZ, a1: C_REG, a6: C_SOREG, type_: 7, size: 4},
	{as: AMOVBZ, a1: C_REG, a6: C_XOREG, type_: 108, size: 4},
	{as: AMOVBZ, a1: C_REG, a6: C_REG, type_: 13, size: 4},

	{as: AMOVD, a1: C_16CON, a6: C_REG, type_: 3, size: 4},
	{as: AMOVD, a1: C_SACON, a6: C_REG, type_: 3, size: 4},
	{as: AMOVD, a1: C_SOREG, a6: C_REG, type_: 8, size: 4},
	{as: AMOVD, a1: C_XOREG, a6: C_REG, type_: 109, size: 4},
	{as: AMOVD, a1: C_SOREG, a6: C_SPR, type_: 107, size: 8},
	{as: AMOVD, a1: C_SPR, a6: C_REG, type_: 66, size: 4},
	{as: AMOVD, a1: C_REG, a6: C_SOREG, type_: 7, size: 4},
	{as: AMOVD, a1: C_REG, a6: C_XOREG, type_: 108, size: 4},
	{as: AMOVD, a1: C_SPR, a6: C_SOREG, type_: 106, size: 8},
	{as: AMOVD, a1: C_REG, a6: C_SPR, type_: 66, size: 4},
	{as: AMOVD, a1: C_REG, a6: C_REG, type_: 13, size: 4},

	{as: AMOVW, a1: C_16CON, a6: C_REG, type_: 3, size: 4},
	{as: AMOVW, a1: C_SACON, a6: C_REG, type_: 3, size: 4},
	{as: AMOVW, a1: C_CREG, a6: C_REG, type_: 68, size: 4},
	{as: AMOVW, a1: C_SOREG, a6: C_REG, type_: 8, size: 4},
	{as: AMOVW, a1: C_XOREG, a6: C_REG, type_: 109, size: 4},
	{as: AMOVW, a1: C_SPR, a6: C_REG, type_: 66, size: 4},
	{as: AMOVW, a1: C_REG, a6: C_CREG, type_: 69, size: 4},
	{as: AMOVW, a1: C_REG, a6: C_SOREG, type_: 7, size: 4},
	{as: AMOVW, a1: C_REG, a6: C_XOREG, type_: 108, size: 4},
	{as: AMOVW, a1: C_REG, a6: C_SPR, type_: 66, size: 4},
	{as: AMOVW, a1: C_REG, a6: C_REG, type_: 13, size: 4},

	{as: AFMOVD, a1: C_S16CON, a6: C_FREG, type_: 24, size: 8},
	{as: AFMOVD, a1: C_SOREG, a6: C_FREG, type_: 8, size: 4},
	{as: AFMOVD, a1: C_XOREG, a6: C_FREG, type_: 109, size: 4},
	{as: AFMOVD, a1: C_ZCON, a6: C_FREG, type_: 24, size: 4},
	{as: AFMOVD, a1: C_FREG, a6: C_FREG, type_: 33, size: 4},
	{as: AFMOVD, a1: C_FREG, a6: C_SOREG, type_: 7, size: 4},
	{as: AFMOVD, a1: C_FREG, a6: C_XOREG, type_: 108, size: 4},

	{as: AFMOVSX, a1: C_XOREG, a6: C_FREG, type_: 45, size: 4},
	{as: AFMOVSX, a1: C_FREG, a6: C_XOREG, type_: 44, size: 4},

	{as: AFMOVSZ, a1: C_ZOREG, a6: C_FREG, type_: 45, size: 4},
	{as: AFMOVSZ, a1: C_XOREG, a6: C_FREG, type_: 45, size: 4},

	{as: AMOVFL, a1: C_CREG, a6: C_CREG, type_: 67, size: 4},
	{as: AMOVFL, a1: C_FPSCR, a6: C_CREG, type_: 73, size: 4},
	{as: AMOVFL, a1: C_FPSCR, a6: C_FREG, type_: 53, size: 4},
	{as: AMOVFL, a1: C_FREG, a3: C_32CON, a6: C_FPSCR, type_: 64, size: 4},
	{as: AMOVFL, a1: C_FREG, a6: C_FPSCR, type_: 64, size: 4},
	{as: AMOVFL, a1: C_32CON, a6: C_FPSCR, type_: 65, size: 4},
	{as: AMOVFL, a1: C_REG, a6: C_CREG, type_: 69, size: 4},
	{as: AMOVFL, a1: C_REG, a6: C_32CON, type_: 69, size: 4},

	{as: ASYSCALL, type_: 5, size: 4},
	{as: ASYSCALL, a1: C_REG, type_: 77, size: 12},
	{as: ASYSCALL, a1: C_U15CON, type_: 77, size: 12},
	{as: ABEQ, a6: C_BRA, type_: 16, size: 4},
	{as: ABEQ, a1: C_CREG, a6: C_BRA, type_: 16, size: 4},
	{as: ABEQ, a1: C_CREG, a6: C_LR, type_: 17, size: 4},
	{as: ABR, a6: C_BRA, type_: 11, size: 4},                                         // b label
	{as: ABR, a6: C_BRAPIC, type_: 11, size: 8},                                      // b label; nop
	{as: ABR, a6: C_LR, type_: 18, size: 4},                                          // blr
	{as: ABR, a6: C_CTR, type_: 18, size: 4},                                         // bctr
	{as: ABC, a1: C_U15CON, a2: C_CRBIT, a6: C_BRA, type_: 16, size: 4},              // bc bo, bi, label
	{as: ABC, a1: C_U15CON, a2: C_CRBIT, a6: C_LR, type_: 18, size: 4},               // bclr bo, bi
	{as: ABC, a1: C_U15CON, a2: C_CRBIT, a3: C_U15CON, a6: C_LR, type_: 18, size: 4}, // bclr bo, bi, bh
	{as: ABC, a1: C_U15CON, a2: C_CRBIT, a6: C_CTR, type_: 18, size: 4},              // bcctr bo, bi
	{as: ABDNZ, a6: C_BRA, type_: 16, size: 4},
	{as: ASYNC, type_: 46, size: 4},
	{as: AWORD, a1: C_32CON, type_: 40, size: 4},
	{as: ADWORD, a1: C_64CON, type_: 31, size: 8},
	{as: ADWORD, a1: C_LACON, type_: 31, size: 8},
	{as: AADDME, a1: C_REG, a6: C_REG, type_: 47, size: 4},
	{as: AEXTSB, a1: C_REG, a6: C_REG, type_: 48, size: 4},
	{as: AEXTSB, a6: C_REG, type_: 48, size: 4},
	{as: AISEL, a1: C_U5CON, a2: C_REG, a3: C_REG, a6: C_REG, type_: 84, size: 4},
	{as: AISEL, a1: C_CRBIT, a2: C_REG, a3: C_REG, a6: C_REG, type_: 84, size: 4},
	{as: ANEG, a1: C_REG, a6: C_REG, type_: 47, size: 4},
	{as: ANEG, a6: C_REG, type_: 47, size: 4},
	{as: AREM, a1: C_REG, a6: C_REG, type_: 50, size: 12},
	{as: AREM, a1: C_REG, a2: C_REG, a6: C_REG, type_: 50, size: 12},
	{as: AREMU, a1: C_REG, a6: C_REG, type_: 50, size: 16},
	{as: AREMU, a1: C_REG, a2: C_REG, a6: C_REG, type_: 50, size: 16},
	{as: AREMD, a1: C_REG, a6: C_REG, type_: 51, size: 12},
	{as: AREMD, a1: C_REG, a2: C_REG, a6: C_REG, type_: 51, size: 12},
	{as: AMTFSB0, a1: C_U15CON, type_: 52, size: 4},
	/* Other ISA 2.05+ instructions */
	{as: APOPCNTD, a1: C_REG, a6: C_REG, type_: 93, size: 4},            /* population count, x-form */
	{as: ACMPB, a1: C_REG, a2: C_REG, a6: C_REG, type_: 92, size: 4},    /* compare byte, x-form */
	{as: ACMPEQB, a1: C_REG, a2: C_REG, a6: C_CREG, type_: 92, size: 4}, /* compare equal byte, x-form, ISA 3.0 */
	{as: ACMPEQB, a1: C_REG, a6: C_REG, type_: 70, size: 4},
	{as: AFTDIV, a1: C_FREG, a2: C_FREG, a6: C_U15CON, type_: 92, size: 4},          /* floating test for sw divide, x-form */
	{as: AFTSQRT, a1: C_FREG, a6: C_U15CON, type_: 93, size: 4},                     /* floating test for sw square root, x-form */
	{as: ACOPY, a1: C_REG, a6: C_REG, type_: 92, size: 4},                           /* copy/paste facility, x-form */
	{as: ADARN, a1: C_U15CON, a6: C_REG, type_: 92, size: 4},                        /* deliver random number, x-form */
	{as: AMADDHD, a1: C_REG, a2: C_REG, a3: C_REG, a6: C_REG, type_: 83, size: 4},   /* multiply-add high/low doubleword, va-form */
	{as: AADDEX, a1: C_REG, a2: C_REG, a3: C_U15CON, a6: C_REG, type_: 94, size: 4}, /* add extended using alternate carry, z23-form */
	{as: ACRAND, a1: C_CRBIT, a2: C_CRBIT, a6: C_CRBIT, type_: 2, size: 4},          /* logical ops for condition register bits xl-form */

	/* Misc ISA 3.0 instructions */
	{as: ASETB, a1: C_CREG, a6: C_REG, type_: 110, size: 4},
	{as: AVCLZLSBB, a1: C_VREG, a6: C_REG, type_: 85, size: 4},

	/* Vector instructions */

	/* Vector load */
	{as: ALVEBX, a1: C_XOREG, a6: C_VREG, type_: 45, size: 4}, /* vector load, x-form */

	/* Vector store */
	{as: ASTVEBX, a1: C_VREG, a6: C_XOREG, type_: 44, size: 4}, /* vector store, x-form */

	/* Vector logical */
	{as: AVAND, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector and, vx-form */
	{as: AVOR, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},  /* vector or, vx-form */

	/* Vector add */
	{as: AVADDUM, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},            /* vector add unsigned modulo, vx-form */
	{as: AVADDCU, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},            /* vector add & write carry unsigned, vx-form */
	{as: AVADDUS, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},            /* vector add unsigned saturate, vx-form */
	{as: AVADDSS, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},            /* vector add signed saturate, vx-form */
	{as: AVADDE, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector add extended, va-form */

	/* Vector subtract */
	{as: AVSUBUM, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},            /* vector subtract unsigned modulo, vx-form */
	{as: AVSUBCU, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},            /* vector subtract & write carry unsigned, vx-form */
	{as: AVSUBUS, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},            /* vector subtract unsigned saturate, vx-form */
	{as: AVSUBSS, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},            /* vector subtract signed saturate, vx-form */
	{as: AVSUBE, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector subtract extended, va-form */

	/* Vector multiply */
	{as: AVMULESB, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},              /* vector multiply, vx-form */
	{as: AVPMSUM, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},               /* vector polynomial multiply & sum, vx-form */
	{as: AVMSUMUDM, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector multiply-sum, va-form */

	/* Vector rotate */
	{as: AVR, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector rotate, vx-form */

	/* Vector shift */
	{as: AVS, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},                 /* vector shift, vx-form */
	{as: AVSA, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},                /* vector shift algebraic, vx-form */
	{as: AVSOI, a1: C_U16CON, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector shift by octet immediate, va-form */

	/* Vector count */
	{as: AVCLZ, a1: C_VREG, a6: C_VREG, type_: 85, size: 4},    /* vector count leading zeros, vx-form */
	{as: AVPOPCNT, a1: C_VREG, a6: C_VREG, type_: 85, size: 4}, /* vector population count, vx-form */

	/* Vector compare */
	{as: AVCMPEQ, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},   /* vector compare equal, vc-form */
	{as: AVCMPGT, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},   /* vector compare greater than, vc-form */
	{as: AVCMPNEZB, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector compare not equal, vx-form */

	/* Vector merge */
	{as: AVMRGOW, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector merge odd word, vx-form */

	/* Vector permute */
	{as: AVPERM, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector permute, va-form */

	/* Vector bit permute */
	{as: AVBPERMQ, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector bit permute, vx-form */

	/* Vector select */
	{as: AVSEL, a1: C_VREG, a2: C_VREG, a3: C_VREG, a6: C_VREG, type_: 83, size: 4}, /* vector select, va-form */

	/* Vector splat */
	{as: AVSPLTB, a1: C_S16CON, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},
	{as: AVSPLTISB, a1: C_S16CON, a6: C_VREG, type_: 82, size: 4},

	/* Vector AES */
	{as: AVCIPH, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4},  /* vector AES cipher, vx-form */
	{as: AVNCIPH, a1: C_VREG, a2: C_VREG, a6: C_VREG, type_: 82, size: 4}, /* vector AES inverse cipher, vx-form */
	{as: AVSBOX, a1: C_VREG, a6: C_VREG, type_: 82, size: 4},              /* vector AES subbytes, vx-form */

	/* Vector SHA */
	{as: AVSHASIGMA, a1: C_U16CON, a2: C_VREG, a3: C_U16CON, a6: C_VREG, type_: 82, size: 4}, /* vector SHA sigma, vx-form */

	/* VSX vector load */
	{as: ALXVD2X, a1: C_XOREG, a6: C_VSREG, type_: 87, size: 4},        /* vsx vector load, xx1-form */
	{as: ALXV, a1: C_SOREG, a6: C_VSREG, type_: 96, size: 4},           /* vsx vector load, dq-form */
	{as: ALXVL, a1: C_REG, a2: C_REG, a6: C_VSREG, type_: 98, size: 4}, /* vsx vector load length */

	/* VSX vector store */
	{as: ASTXVD2X, a1: C_VSREG, a6: C_XOREG, type_: 86, size: 4},        /* vsx vector store, xx1-form */
	{as: ASTXV, a1: C_VSREG, a6: C_SOREG, type_: 97, size: 4},           /* vsx vector store, dq-form */
	{as: ASTXVL, a1: C_VSREG, a2: C_REG, a6: C_REG, type_: 99, size: 4}, /* vsx vector store with length x-form */

	/* VSX scalar load */
	{as: ALXSDX, a1: C_XOREG, a6: C_VSREG, type_: 87, size: 4}, /* vsx scalar load, xx1-form */

	/* VSX scalar store */
	{as: ASTXSDX, a1: C_VSREG, a6: C_XOREG, type_: 86, size: 4}, /* vsx scalar store, xx1-form */

	/* VSX scalar as integer load */
	{as: ALXSIWAX, a1: C_XOREG, a6: C_VSREG, type_: 87, size: 4}, /* vsx scalar as integer load, xx1-form */

	/* VSX scalar store as integer */
	{as: ASTXSIWX, a1: C_VSREG, a6: C_XOREG, type_: 86, size: 4}, /* vsx scalar as integer store, xx1-form */

	/* VSX move from VSR */
	{as: AMFVSRD, a1: C_VSREG, a6: C_REG, type_: 88, size: 4},
	{as: AMFVSRD, a1: C_FREG, a6: C_REG, type_: 88, size: 4},

	/* VSX move to VSR */
	{as: AMTVSRD, a1: C_REG, a6: C_VSREG, type_: 104, size: 4},
	{as: AMTVSRD, a1: C_REG, a6: C_FREG, type_: 104, size: 4},
	{as: AMTVSRDD, a1: C_REG, a2: C_REG, a6: C_VSREG, type_: 104, size: 4},

	/* VSX xx3-form */
	{as: AXXLAND, a1: C_FREG, a2: C_FREG, a6: C_FREG, type_: 90, size: 4},    /* vsx xx3-form (FPR usage) */
	{as: AXXLAND, a1: C_VSREG, a2: C_VSREG, a6: C_VSREG, type_: 90, size: 4}, /* vsx xx3-form */

	/* VSX select */
	{as: AXXSEL, a1: C_VSREG, a2: C_VSREG, a3: C_VSREG, a6: C_VSREG, type_: 91, size: 4}, /* vsx select, xx4-form */

	/* VSX merge */
	{as: AXXMRGHW, a1: C_VSREG, a2: C_VSREG, a6: C_VSREG, type_: 90, size: 4}, /* vsx merge, xx3-form */

	/* VSX splat */
	{as: AXXSPLTW, a1: C_VSREG, a3: C_U15CON, a6: C_VSREG, type_: 89, size: 4}, /* vsx splat, xx2-form */
	{as: AXXSPLTIB, a1: C_U15CON, a6: C_VSREG, type_: 100, size: 4},            /* vsx splat, xx2-form */

	/* VSX permute */
	{as: AXXPERM, a1: C_VSREG, a2: C_VSREG, a6: C_VSREG, type_: 90, size: 4}, /* vsx permute, xx3-form */

	/* VSX shift */
	{as: AXXSLDWI, a1: C_VSREG, a2: C_VSREG, a3: C_U15CON, a6: C_VSREG, type_: 90, size: 4}, /* vsx shift immediate, xx3-form */

	/* VSX reverse bytes */
	{as: AXXBRQ, a1: C_VSREG, a6: C_VSREG, type_: 101, size: 4}, /* vsx reverse bytes */

	/* VSX scalar FP-FP conversion */
	{as: AXSCVDPSP, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx scalar fp-fp conversion, xx2-form */

	/* VSX vector FP-FP conversion */
	{as: AXVCVDPSP, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx vector fp-fp conversion, xx2-form */

	/* VSX scalar FP-integer conversion */
	{as: AXSCVDPSXDS, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx scalar fp-integer conversion, xx2-form */

	/* VSX scalar integer-FP conversion */
	{as: AXSCVSXDDP, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx scalar integer-fp conversion, xx2-form */

	/* VSX vector FP-integer conversion */
	{as: AXVCVDPSXDS, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx vector fp-integer conversion, xx2-form */

	/* VSX vector integer-FP conversion */
	{as: AXVCVSXDDP, a1: C_VSREG, a6: C_VSREG, type_: 89, size: 4}, /* vsx vector integer-fp conversion, xx2-form */

	{as: ACMP, a1: C_REG, a6: C_REG, type_: 70, size: 4},
	{as: ACMP, a1: C_REG, a2: C_CREG, a6: C_REG, type_: 70, size: 4},
	{as: ACMP, a1: C_REG, a6: C_S16CON, type_: 70, size: 4},
	{as: ACMP, a1: C_REG, a2: C_CREG, a6: C_S16CON, type_: 70, size: 4},
	{as: ACMPU, a1: C_REG, a6: C_REG, type_: 70, size: 4},
	{as: ACMPU, a1: C_REG, a2: C_CREG, a6: C_REG, type_: 70, size: 4},
	{as: ACMPU, a1: C_REG, a6: C_U16CON, type_: 70, size: 4},
	{as: ACMPU, a1: C_REG, a2: C_CREG, a6: C_U16CON, type_: 70, size: 4},
	{as: AFCMPO, a1: C_FREG, a6: C_FREG, type_: 70, size: 4},
	{as: AFCMPO, a1: C_FREG, a2: C_CREG, a6: C_FREG, type_: 70, size: 4},
	{as: ADCMPOQ, a1: C_FREGP, a6: C_FREGP, type_: 70, size: 4},
	{as: ADCMPOQ, a1: C_FREGP, a2: C_CREG, a6: C_FREGP, type_: 70, size: 4},
	{as: ATW, a1: C_32CON, a2: C_REG, a6: C_REG, type_: 60, size: 4},
	{as: ATW, a1: C_32CON, a2: C_REG, a6: C_S16CON, type_: 61, size: 4},
	{as: ADCBF, a1: C_SOREG, type_: 43, size: 4},
	{as: ADCBF, a1: C_XOREG, type_: 43, size: 4},
	{as: ADCBF, a1: C_XOREG, a2: C_REG, a6: C_U15CON, type_: 43, size: 4},
	{as: ADCBF, a1: C_SOREG, a6: C_U15CON, type_: 43, size: 4},
	{as: ADCBF, a1: C_XOREG, a6: C_U15CON, type_: 43, size: 4},
	{as: ASTDCCC, a1: C_REG, a2: C_REG, a6: C_XOREG, type_: 44, size: 4},
	{as: ASTDCCC, a1: C_REG, a6: C_XOREG, type_: 44, size: 4},
	{as: ALDAR, a1: C_XOREG, a6: C_REG, type_: 45, size: 4},
	{as: ALDAR, a1: C_XOREG, a3: C_U16CON, a6: C_REG, type_: 45, size: 4},
	{as: AEIEIO, type_: 46, size: 4},
	{as: ATLBIE, a1: C_REG, type_: 49, size: 4},
	{as: ATLBIE, a1: C_U15CON, a6: C_REG, type_: 49, size: 4},
	{as: ASLBMFEE, a1: C_REG, a6: C_REG, type_: 55, size: 4},
	{as: ASLBMTE, a1: C_REG, a6: C_REG, type_: 55, size: 4},
	{as: ASTSW, a1: C_REG, a6: C_XOREG, type_: 44, size: 4},
	{as: ASTSW, a1: C_REG, a3: C_32CON, a6: C_ZOREG, type_: 41, size: 4},
	{as: ALSW, a1: C_XOREG, a6: C_REG, type_: 45, size: 4},
	{as: ALSW, a1: C_ZOREG, a3: C_32CON, a6: C_REG, type_: 42, size: 4},

	{as: obj.AUNDEF, type_: 78, size: 4},
	{as: obj.APCDATA, a1: C_32CON, a6: C_32CON, type_: 0, size: 0},
	{as: obj.AFUNCDATA, a1: C_U15CON, a6: C_ADDR, type_: 0, size: 0},
	{as: obj.ANOP, type_: 0, size: 0},
	{as: obj.ANOP, a1: C_32CON, type_: 0, size: 0}, // NOP operand variations added for #40689
	{as: obj.ANOP, a1: C_REG, type_: 0, size: 0},   // to preserve previous behavior
	{as: obj.ANOP, a1: C_FREG, type_: 0, size: 0},
	{as: obj.ADUFFZERO, a6: C_BRA, type_: 11, size: 4}, // same as ABR/ABL
	{as: obj.ADUFFCOPY, a6: C_BRA, type_: 11, size: 4}, // same as ABR/ABL
	{as: obj.APCALIGN, a1: C_32CON, type_: 0, size: 0}, // align code
}

// These are opcodes above which may generate different sequences depending on whether prefix opcode support
// is available
type PrefixableOptab struct {
	Optab
	minGOPPC64 int  // Minimum GOPPC64 required to support this.
	pfxsize    int8 // Instruction sequence size when prefixed opcodes are used
}

// The prefixable optab entry contains the pseudo-opcodes which generate relocations, or may generate
// a more efficient sequence of instructions if a prefixed version exists (ex. paddi instead of oris/ori/add).
//
// This table is meant to transform all sequences which might be TOC-relative into an equivalent PC-relative
// sequence. It also encompasses several transformations which do not involve relocations, those could be
// separated and applied to AIX and other non-ELF targets. Likewise, the prefixed forms do not have encoding
// restrictions on the offset, so they are also used for static binary to allow better code generation. e.x
//
//	MOVD something-byte-aligned(Rx), Ry
//	MOVD 3(Rx), Ry
//
// is allowed when the prefixed forms are used.
//
// This requires an ISA 3.1 compatible cpu (e.g Power10), and when linking externally an ELFv2 1.5 compliant.
var prefixableOptab = []PrefixableOptab{
	{Optab: Optab{as: AMOVD, a1: C_S34CON, a6: C_REG, type_: 19, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVD, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVD, a1: C_TLS_LE, a6: C_REG, type_: 79, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVD, a1: C_TLS_IE, a6: C_REG, type_: 80, size: 12}, minGOPPC64: 10, pfxsize: 12},
	{Optab: Optab{as: AMOVD, a1: C_LACON, a6: C_REG, type_: 26, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVD, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVD, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVD, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, minGOPPC64: 10, pfxsize: 8},

	{Optab: Optab{as: AMOVW, a1: C_32CON, a6: C_REG, type_: 19, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVW, a1: C_LACON, a6: C_REG, type_: 26, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVW, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVW, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVW, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVW, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, minGOPPC64: 10, pfxsize: 8},

	{Optab: Optab{as: AMOVB, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVB, a1: C_LOREG, a6: C_REG, type_: 36, size: 12}, minGOPPC64: 10, pfxsize: 12},
	{Optab: Optab{as: AMOVB, a1: C_ADDR, a6: C_REG, type_: 75, size: 12}, minGOPPC64: 10, pfxsize: 12},
	{Optab: Optab{as: AMOVB, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, minGOPPC64: 10, pfxsize: 8},

	{Optab: Optab{as: AMOVBZ, a1: C_LOREG, a6: C_REG, type_: 36, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVBZ, a1: C_ADDR, a6: C_REG, type_: 75, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVBZ, a1: C_REG, a6: C_LOREG, type_: 35, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AMOVBZ, a1: C_REG, a6: C_ADDR, type_: 74, size: 8}, minGOPPC64: 10, pfxsize: 8},

	{Optab: Optab{as: AFMOVD, a1: C_LOREG, a6: C_FREG, type_: 36, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AFMOVD, a1: C_ADDR, a6: C_FREG, type_: 75, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AFMOVD, a1: C_FREG, a6: C_LOREG, type_: 35, size: 8}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AFMOVD, a1: C_FREG, a6: C_ADDR, type_: 74, size: 8}, minGOPPC64: 10, pfxsize: 8},

	{Optab: Optab{as: AADD, a1: C_32CON, a2: C_REG, a6: C_REG, type_: 22, size: 12}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AADD, a1: C_32CON, a6: C_REG, type_: 22, size: 12}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AADD, a1: C_S34CON, a2: C_REG, a6: C_REG, type_: 22, size: 20}, minGOPPC64: 10, pfxsize: 8},
	{Optab: Optab{as: AADD, a1: C_S34CON, a6: C_REG, type_: 22, size: 20}, minGOPPC64: 10, pfxsize: 8},
}

var oprange [ALAST & obj.AMask][]Optab

var xcmp [C_NCLASS][C_NCLASS]bool

var pfxEnabled = false // ISA 3.1 prefixed instructions are supported.
var buildOpCfg = ""    // Save the os/cpu/arch tuple used to configure the assembler in buildop

// padding bytes to add to align code as requested.
func addpad(pc, a int64, ctxt *obj.Link, cursym *obj.LSym) int {
	switch a {
	case 8, 16, 32, 64:
		// By default function alignment is 16. If an alignment > 16 is
		// requested then the function alignment must also be promoted.
		// The function alignment is not promoted on AIX at this time.
		// TODO: Investigate AIX function alignment.
		if ctxt.Headtype != objabi.Haix && cursym.Func().Align < int32(a) {
			cursym.Func().Align = int32(a)
		}
		if pc&(a-1) != 0 {
			return int(a - (pc & (a - 1)))
		}
	default:
		ctxt.Diag("Unexpected alignment: %d for PCALIGN directive\n", a)
	}
	return 0
}

func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
	p := cursym.Func().Text
	if p == nil || p.Link == nil { // handle external functions and ELF section symbols
		return
	}

	if oprange[AANDN&obj.AMask] == nil {
		ctxt.Diag("ppc64 ops not initialized, call ppc64.buildop first")
	}

	c := ctxt9{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: int32(p.To.Offset)}

	pc := int64(0)
	p.Pc = pc

	var m int
	var o *Optab
	for p = p.Link; p != nil; p = p.Link {
		p.Pc = pc
		o = c.oplook(p)
		m = int(o.size)
		if m == 0 {
			if p.As == obj.APCALIGN {
				a := c.vregoff(&p.From)
				m = addpad(pc, a, ctxt, cursym)
			} else {
				if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
					ctxt.Diag("zero-width instruction\n%v", p)
				}
				continue
			}
		}
		pc += int64(m)
	}

	c.cursym.Size = pc

	/*
	 * if any procedure is large enough to
	 * generate a large SBRA branch, then
	 * generate extra passes putting branches
	 * around jmps to fix. this is rare.
	 */
	bflag := 1

	var otxt int64
	var q *obj.Prog
	var out [5]uint32
	var falign int32 // Track increased alignment requirements for prefix.
	for bflag != 0 {
		bflag = 0
		pc = 0
		falign = 0 // Note, linker bumps function symbols to funcAlign.
		for p = c.cursym.Func().Text.Link; p != nil; p = p.Link {
			p.Pc = pc
			o = c.oplook(p)

			// very large conditional branches
			if (o.type_ == 16 || o.type_ == 17) && p.To.Target() != nil {
				otxt = p.To.Target().Pc - pc
				if otxt < -(1<<15)+10 || otxt >= (1<<15)-10 {
					// Assemble the instruction with a target not too far to figure out BI and BO fields.
					// If only the CTR or BI (the CR bit) are tested, the conditional branch can be inverted,
					// and only one extra branch is needed to reach the target.
					tgt := p.To.Target()
					p.To.SetTarget(p.Link)
					o.asmout(&c, p, o, &out)
					p.To.SetTarget(tgt)

					bo := int64(out[0]>>21) & 31
					bi := int16((out[0] >> 16) & 31)
					invertible := false

					if bo&0x14 == 0x14 {
						// A conditional branch that is unconditionally taken. This cannot be inverted.
					} else if bo&0x10 == 0x10 {
						// A branch based on the value of CTR. Invert the CTR comparison against zero bit.
						bo ^= 0x2
						invertible = true
					} else if bo&0x04 == 0x04 {
						// A branch based on CR bit. Invert the BI comparison bit.
						bo ^= 0x8
						invertible = true
					}

					if invertible {
						// Rewrite
						//     BC bo,...,far_away_target
						//     NEXT_INSN
						// to:
						//     BC invert(bo),next_insn
						//     JMP far_away_target
						//   next_insn:
						//     NEXT_INSN
						p.As = ABC
						p.From = obj.Addr{Type: obj.TYPE_CONST, Name: obj.NAME_NONE, Offset: bo}
						q = c.newprog()
						q.As = ABR
						q.To.Type = obj.TYPE_BRANCH
						q.To.SetTarget(p.To.Target())
						q.Link = p.Link
						p.To.SetTarget(p.Link)
						p.Link = q
						p.Reg = REG_CRBIT0 + bi
					} else {
						// Rewrite
						//     BC ...,far_away_target
						//     NEXT_INSN
						// to
						//     BC ...,tmp
						//     JMP next_insn
						//   tmp:
						//     JMP far_away_target
						//   next_insn:
						//     NEXT_INSN
						q = c.newprog()
						q.Link = p.Link
						p.Link = q
						q.As = ABR
						q.To.Type = obj.TYPE_BRANCH
						q.To.SetTarget(p.To.Target())
						p.To.SetTarget(q)
						q = c.newprog()
						q.Link = p.Link
						p.Link = q
						q.As = ABR
						q.To.Type = obj.TYPE_BRANCH
						q.To.SetTarget(q.Link.Link)
					}
					bflag = 1
				}
			}

			m = int(o.size)
			if m == 0 {
				if p.As == obj.APCALIGN {
					a := c.vregoff(&p.From)
					m = addpad(pc, a, ctxt, cursym)
				} else {
					if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
						ctxt.Diag("zero-width instruction\n%v", p)
					}
					continue
				}
			}

			// Prefixed instructions cannot be placed across a 64B boundary.
			// Mark and adjust the PC of those which do. A nop will be
			// inserted during final assembly.
			if o.ispfx {
				mark := p.Mark &^ PFX_X64B
				if pc&63 == 60 {
					p.Pc += 4
					m += 4
					mark |= PFX_X64B
				}

				// Marks may be adjusted if a too-far conditional branch is
				// fixed up above. Likewise, inserting a NOP may cause a
				// branch target to become too far away.  We need to run
				// another iteration and verify no additional changes
				// are needed.
				if mark != p.Mark {
					bflag = 1
					p.Mark = mark
				}

				// Check for 16 or 32B crossing of this prefixed insn.
				// These do no require padding, but do require increasing
				// the function alignment to prevent them from potentially
				// crossing a 64B boundary when the linker assigns the final
				// PC.
				switch p.Pc & 31 {
				case 28: // 32B crossing
					falign = 64
				case 12: // 16B crossing
					if falign < 64 {
						falign = 32
					}
				}
			}

			pc += int64(m)
		}

		c.cursym.Size = pc
	}

	c.cursym.Size = pc
	c.cursym.Func().Align = falign
	c.cursym.Grow(c.cursym.Size)

	// lay out the code, emitting code and data relocations.

	bp := c.cursym.P
	var i int32
	for p := c.cursym.Func().Text.Link; p != nil; p = p.Link {
		c.pc = p.Pc
		o = c.oplook(p)
		if int(o.size) > 4*len(out) {
			log.Fatalf("out array in span9 is too small, need at least %d for %v", o.size/4, p)
		}
		// asmout is not set up to add large amounts of padding
		if o.type_ == 0 && p.As == obj.APCALIGN {
			aln := c.vregoff(&p.From)
			v := addpad(p.Pc, aln, c.ctxt, c.cursym)
			if v > 0 {
				// Same padding instruction for all
				for i = 0; i < int32(v/4); i++ {
					c.ctxt.Arch.ByteOrder.PutUint32(bp, NOP)
					bp = bp[4:]
				}
			}
		} else {
			if p.Mark&PFX_X64B != 0 {
				c.ctxt.Arch.ByteOrder.PutUint32(bp, NOP)
				bp = bp[4:]
			}
			o.asmout(&c, p, o, &out)
			for i = 0; i < int32(o.size/4); i++ {
				c.ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
				bp = bp[4:]
			}
		}
	}
}

func isint32(v int64) bool {
	return int64(int32(v)) == v
}

func isuint32(v uint64) bool {
	return uint64(uint32(v)) == v
}

func (c *ctxt9) aclassreg(reg int16) int {
	if REG_R0 <= reg && reg <= REG_R31 {
		return C_REGP + int(reg&1)
	}
	if REG_F0 <= reg && reg <= REG_F31 {
		return C_FREGP + int(reg&1)
	}
	if REG_V0 <= reg && reg <= REG_V31 {
		return C_VREG
	}
	if REG_VS0 <= reg && reg <= REG_VS63 {
		return C_VSREGP + int(reg&1)
	}
	if REG_CR0 <= reg && reg <= REG_CR7 || reg == REG_CR {
		return C_CREG
	}
	if REG_CR0LT <= reg && reg <= REG_CR7SO {
		return C_CRBIT
	}
	if REG_SPR0 <= reg && reg <= REG_SPR0+1023 {
		switch reg {
		case REG_LR:
			return C_LR

		case REG_CTR:
			return C_CTR
		}

		return C_SPR
	}
	if REG_A0 <= reg && reg <= REG_A7 {
		return C_AREG
	}
	if reg == REG_FPSCR {
		return C_FPSCR
	}
	return C_GOK
}

func (c *ctxt9) aclass(a *obj.Addr) int {
	switch a.Type {
	case obj.TYPE_NONE:
		return C_NONE

	case obj.TYPE_REG:
		return c.aclassreg(a.Reg)

	case obj.TYPE_MEM:
		if a.Index != 0 {
			if a.Name != obj.NAME_NONE || a.Offset != 0 {
				c.ctxt.Logf("Unexpected Instruction operand index %d offset %d class %d \n", a.Index, a.Offset, a.Class)

			}
			return C_XOREG
		}
		switch a.Name {
		case obj.NAME_GOTREF, obj.NAME_TOCREF:
			return C_ADDR

		case obj.NAME_EXTERN,
			obj.NAME_STATIC:
			c.instoffset = a.Offset
			if a.Sym == nil {
				break
			} else if a.Sym.Type == objabi.STLSBSS {
				// For PIC builds, use 12 byte got initial-exec TLS accesses.
				if c.ctxt.Flag_shared {
					return C_TLS_IE
				}
				// Otherwise, use 8 byte local-exec TLS accesses.
				return C_TLS_LE
			} else {
				return C_ADDR
			}

		case obj.NAME_AUTO:
			a.Reg = REGSP
			c.instoffset = int64(c.autosize) + a.Offset
			if c.instoffset >= -BIG && c.instoffset < BIG {
				return C_SOREG
			}
			return C_LOREG

		case obj.NAME_PARAM:
			a.Reg = REGSP
			c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.Arch.FixedFrameSize
			if c.instoffset >= -BIG && c.instoffset < BIG {
				return C_SOREG
			}
			return C_LOREG

		case obj.NAME_NONE:
			c.instoffset = a.Offset
			if a.Offset == 0 && a.Index == 0 {
				return C_ZOREG
			} else if c.instoffset >= -BIG && c.instoffset < BIG {
				return C_SOREG
			} else {
				return C_LOREG
			}
		}

		return C_GOK

	case obj.TYPE_TEXTSIZE:
		return C_TEXTSIZE

	case obj.TYPE_FCONST:
		// The only cases where FCONST will occur are with float64 +/- 0.
		// All other float constants are generated in memory.
		f64 := a.Val.(float64)
		if f64 == 0 {
			if math.Signbit(f64) {
				return C_S16CON
			}
			return C_ZCON
		}
		log.Fatalf("Unexpected nonzero FCONST operand %v", a)

	case obj.TYPE_CONST,
		obj.TYPE_ADDR:
		switch a.Name {
		case obj.NAME_NONE:
			c.instoffset = a.Offset
			if a.Reg != 0 {
				if -BIG <= c.instoffset && c.instoffset < BIG {
					return C_SACON
				}
				if isint32(c.instoffset) {
					return C_LACON
				}
				return C_DACON
			}

		case obj.NAME_EXTERN,
			obj.NAME_STATIC:
			s := a.Sym
			if s == nil {
				return C_GOK
			}
			c.instoffset = a.Offset
			return C_LACON

		case obj.NAME_AUTO:
			a.Reg = REGSP
			c.instoffset = int64(c.autosize) + a.Offset
			if c.instoffset >= -BIG && c.instoffset < BIG {
				return C_SACON
			}
			return C_LACON

		case obj.NAME_PARAM:
			a.Reg = REGSP
			c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.Arch.FixedFrameSize
			if c.instoffset >= -BIG && c.instoffset < BIG {
				return C_SACON
			}
			return C_LACON

		default:
			return C_GOK
		}

		if c.instoffset >= 0 {
			sbits := bits.Len64(uint64(c.instoffset))
			switch {
			case sbits <= 5:
				return C_ZCON + sbits
			case sbits <= 8:
				return C_U8CON
			case sbits <= 15:
				return C_U15CON
			case sbits <= 16:
				return C_U16CON
			case sbits <= 31:
				return C_U31CON
			case sbits <= 32:
				return C_U32CON
			case sbits <= 33:
				return C_S34CON
			default:
				return C_64CON
			}
		} else {
			sbits := bits.Len64(uint64(^c.instoffset))
			switch {
			case sbits <= 15:
				return C_S16CON
			case sbits <= 31:
				return C_S32CON
			case sbits <= 33:
				return C_S34CON
			default:
				return C_64CON
			}
		}

	case obj.TYPE_BRANCH:
		if a.Sym != nil && c.ctxt.Flag_dynlink && !pfxEnabled {
			return C_BRAPIC
		}
		return C_BRA
	}

	return C_GOK
}

func prasm(p *obj.Prog) {
	fmt.Printf("%v\n", p)
}

func (c *ctxt9) oplook(p *obj.Prog) *Optab {
	a1 := int(p.Optab)
	if a1 != 0 {
		return &optab[a1-1]
	}
	a1 = int(p.From.Class)
	if a1 == 0 {
		a1 = c.aclass(&p.From) + 1
		p.From.Class = int8(a1)
	}
	a1--

	argsv := [3]int{C_NONE + 1, C_NONE + 1, C_NONE + 1}
	for i, ap := range p.RestArgs {
		argsv[i] = int(ap.Addr.Class)
		if argsv[i] == 0 {
			argsv[i] = c.aclass(&ap.Addr) + 1
			ap.Addr.Class = int8(argsv[i])
		}

	}
	a3 := argsv[0] - 1
	a4 := argsv[1] - 1
	a5 := argsv[2] - 1

	a6 := int(p.To.Class)
	if a6 == 0 {
		a6 = c.aclass(&p.To) + 1
		p.To.Class = int8(a6)
	}
	a6--

	a2 := C_NONE
	if p.Reg != 0 {
		a2 = c.aclassreg(p.Reg)
	}

	// c.ctxt.Logf("oplook %v %d %d %d %d\n", p, a1, a2, a3, a4, a5, a6)
	ops := oprange[p.As&obj.AMask]
	c1 := &xcmp[a1]
	c2 := &xcmp[a2]
	c3 := &xcmp[a3]
	c4 := &xcmp[a4]
	c5 := &xcmp[a5]
	c6 := &xcmp[a6]
	for i := range ops {
		op := &ops[i]
		if c1[op.a1] && c2[op.a2] && c3[op.a3] && c4[op.a4] && c5[op.a5] && c6[op.a6] {
			p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
			return op
		}
	}

	c.ctxt.Diag("illegal combination %v %v %v %v %v %v %v", p.As, DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4), DRconv(a5), DRconv(a6))
	prasm(p)
	if ops == nil {
		ops = optab
	}
	return &ops[0]
}

// Compare two operand types (ex C_REG, or C_U15CON)
// and return true if b is compatible with a.
//
// Argument comparison isn't reflexitive, so care must be taken.
// a is the argument type as found in optab, b is the argument as
// fitted by aclass.
func cmp(a int, b int) bool {
	if a == b {
		return true
	}
	switch a {

	case C_SPR:
		if b == C_LR || b == C_CTR {
			return true
		}

	case C_U1CON:
		return cmp(C_ZCON, b)
	case C_U2CON:
		return cmp(C_U1CON, b)
	case C_U3CON:
		return cmp(C_U2CON, b)
	case C_U4CON:
		return cmp(C_U3CON, b)
	case C_U5CON:
		return cmp(C_U4CON, b)
	case C_U8CON:
		return cmp(C_U5CON, b)
	case C_U15CON:
		return cmp(C_U8CON, b)
	case C_S16CON:
		return cmp(C_U15CON, b)
	case C_U16CON:
		return cmp(C_U15CON, b)
	case C_16CON:
		return cmp(C_S16CON, b) || cmp(C_U16CON, b)
	case C_U31CON:
		return cmp(C_U16CON, b)
	case C_U32CON:
		return cmp(C_U31CON, b)
	case C_S32CON:
		return cmp(C_U31CON, b) || cmp(C_S16CON, b)
	case C_32CON:
		return cmp(C_S32CON, b) || cmp(C_U32CON, b)
	case C_S34CON:
		return cmp(C_32CON, b)
	case C_64CON:
		return cmp(C_S34CON, b)

	case C_LACON:
		return cmp(C_SACON, b)

	case C_SOREG:
		return cmp(C_ZOREG, b)

	case C_LOREG:
		return cmp(C_SOREG, b)

	case C_XOREG:
		return cmp(C_REG, b) || cmp(C_ZOREG, b)

	// An even/odd register input always matches the regular register types.
	case C_REG:
		return cmp(C_REGP, b) || (b == C_ZCON && r0iszero != 0)
	case C_FREG:
		return cmp(C_FREGP, b)
	case C_VSREG:
		/* Allow any VR argument as a VSR operand. */
		return cmp(C_VSREGP, b) || cmp(C_VREG, b)

	case C_ANY:
		return true
	}

	return false
}

// Used when sorting the optab. Sorting is
// done in a way so that the best choice of
// opcode/operand combination is considered first.
func optabLess(i, j int) bool {
	p1 := &optab[i]
	p2 := &optab[j]
	n := int(p1.as) - int(p2.as)
	// same opcode
	if n != 0 {
		return n < 0
	}
	// Consider those that generate fewer
	// instructions first.
	n = int(p1.size) - int(p2.size)
	if n != 0 {
		return n < 0
	}
	// operand order should match
	// better choices first
	n = int(p1.a1) - int(p2.a1)
	if n != 0 {
		return n < 0
	}
	n = int(p1.a2) - int(p2.a2)
	if n != 0 {
		return n < 0
	}
	n = int(p1.a3) - int(p2.a3)
	if n != 0 {
		return n < 0
	}
	n = int(p1.a4) - int(p2.a4)
	if n != 0 {
		return n < 0
	}
	n = int(p1.a5) - int(p2.a5)
	if n != 0 {
		return n < 0
	}
	n = int(p1.a6) - int(p2.a6)
	if n != 0 {
		return n < 0
	}
	return false
}

// Add an entry to the opcode table for
// a new opcode b0 with the same operand combinations
// as opcode a.
func opset(a, b0 obj.As) {
	oprange[a&obj.AMask] = oprange[b0]
}

// Determine if the build configuration requires a TOC pointer.
// It is assumed this always called after buildop.
func NeedTOCpointer(ctxt *obj.Link) bool {
	return !pfxEnabled && ctxt.Flag_shared
}

// Build the opcode table
func buildop(ctxt *obj.Link) {
	// Limit PC-relative prefix instruction usage to supported and tested targets.
	pfxEnabled = buildcfg.GOPPC64 >= 10 && buildcfg.GOOS == "linux"
	cfg := fmt.Sprintf("power%d/%s/%s", buildcfg.GOPPC64, buildcfg.GOARCH, buildcfg.GOOS)
	if cfg == buildOpCfg {
		// Already initialized to correct OS/cpu; stop now.
		// This happens in the cmd/asm tests,
		// each of which re-initializes the arch.
		return
	}
	buildOpCfg = cfg

	// Configure the optab entries which may generate prefix opcodes.
	prefixOptab := make([]Optab, 0, len(prefixableOptab))
	for _, entry := range prefixableOptab {
		entry := entry
		if pfxEnabled && buildcfg.GOPPC64 >= entry.minGOPPC64 {
			// Enable prefix opcode generation and resize.
			entry.ispfx = true
			entry.size = entry.pfxsize
		}
		prefixOptab = append(prefixOptab, entry.Optab)

	}

	for i := 0; i < C_NCLASS; i++ {
		for n := 0; n < C_NCLASS; n++ {
			if cmp(n, i) {
				xcmp[i][n] = true
			}
		}
	}

	// Append the generated entries, sort, and fill out oprange.
	optab = make([]Optab, 0, len(optabBase)+len(optabGen)+len(prefixOptab))
	optab = append(optab, optabBase...)
	optab = append(optab, optabGen...)
	optab = append(optab, prefixOptab...)
	sort.Slice(optab, optabLess)

	for i := range optab {
		// Use the legacy assembler function if none provided.
		if optab[i].asmout == nil {
			optab[i].asmout = asmout
		}
	}

	for i := 0; i < len(optab); {
		r := optab[i].as
		r0 := r & obj.AMask
		start := i
		for i < len(optab) && optab[i].as == r {
			i++
		}
		oprange[r0] = optab[start:i]

		switch r {
		default:
			if !opsetGen(r) {
				ctxt.Diag("unknown op in build: %v", r)
				log.Fatalf("instruction missing from switch in asm9.go:buildop: %v", r)
			}

		case ADCBF: /* unary indexed: op (b+a); op (b) */
			opset(ADCBI, r0)

			opset(ADCBST, r0)
			opset(ADCBT, r0)
			opset(ADCBTST, r0)
			opset(ADCBZ, r0)
			opset(AICBI, r0)

		case ASTDCCC: /* indexed store: op s,(b+a); op s,(b) */
			opset(ASTWCCC, r0)
			opset(ASTHCCC, r0)
			opset(ASTBCCC, r0)

		case AREM: /* macro */
			opset(AREM, r0)

		case AREMU:
			opset(AREMU, r0)

		case AREMD:
			opset(AREMDU, r0)

		case AMULLW:
			opset(AMULLD, r0)

		case ADIVW: /* op Rb[,Ra],Rd */
			opset(AMULHW, r0)

			opset(AMULHWCC, r0)
			opset(AMULHWU, r0)
			opset(AMULHWUCC, r0)
			opset(AMULLWCC, r0)
			opset(AMULLWVCC, r0)
			opset(AMULLWV, r0)
			opset(ADIVWCC, r0)
			opset(ADIVWV, r0)
			opset(ADIVWVCC, r0)
			opset(ADIVWU, r0)
			opset(ADIVWUCC, r0)
			opset(ADIVWUV, r0)
			opset(ADIVWUVCC, r0)
			opset(AMODUD, r0)
			opset(AMODUW, r0)
			opset(AMODSD, r0)
			opset(AMODSW, r0)
			opset(AADDCC, r0)
			opset(AADDCV, r0)
			opset(AADDCVCC, r0)
			opset(AADDV, r0)
			opset(AADDVCC, r0)
			opset(AADDE, r0)
			opset(AADDECC, r0)
			opset(AADDEV, r0)
			opset(AADDEVCC, r0)
			opset(AMULHD, r0)
			opset(AMULHDCC, r0)
			opset(AMULHDU, r0)
			opset(AMULHDUCC, r0)
			opset(AMULLDCC, r0)
			opset(AMULLDVCC, r0)
			opset(AMULLDV, r0)
			opset(ADIVD, r0)
			opset(ADIVDCC, r0)
			opset(ADIVDE, r0)
			opset(ADIVDEU, r0)
			opset(ADIVDECC, r0)
			opset(ADIVDEUCC, r0)
			opset(ADIVDVCC, r0)
			opset(ADIVDV, r0)
			opset(ADIVDU, r0)
			opset(ADIVDUV, r0)
			opset(ADIVDUVCC, r0)
			opset(ADIVDUCC, r0)

		case ACRAND:
			opset(ACRANDN, r0)
			opset(ACREQV, r0)
			opset(ACRNAND, r0)
			opset(ACRNOR, r0)
			opset(ACROR, r0)
			opset(ACRORN, r0)
			opset(ACRXOR, r0)

		case APOPCNTD: /* popcntd, popcntw, popcntb, cnttzw, cnttzd */
			opset(APOPCNTW, r0)
			opset(APOPCNTB, r0)
			opset(ACNTTZW, r0)
			opset(ACNTTZWCC, r0)
			opset(ACNTTZD, r0)
			opset(ACNTTZDCC, r0)

		case ACOPY: /* copy, paste. */
			opset(APASTECC, r0)

		case AMADDHD: /* maddhd, maddhdu, maddld */
			opset(AMADDHDU, r0)
			opset(AMADDLD, r0)

		case AMOVBZ: /* lbz, stz, rlwm(r/r), lhz, lha, stz, and x variants */
			opset(AMOVH, r0)
			opset(AMOVHZ, r0)

		case AMOVBZU: /* lbz[x]u, stb[x]u, lhz[x]u, lha[x]u, sth[u]x, ld[x]u, std[u]x */
			opset(AMOVHU, r0)

			opset(AMOVHZU, r0)
			opset(AMOVWU, r0)
			opset(AMOVWZU, r0)
			opset(AMOVDU, r0)
			opset(AMOVMW, r0)

		case ALVEBX: /* lvebx, lvehx, lvewx, lvx, lvxl, lvsl, lvsr */
			opset(ALVEHX, r0)
			opset(ALVEWX, r0)
			opset(ALVX, r0)
			opset(ALVXL, r0)
			opset(ALVSL, r0)
			opset(ALVSR, r0)

		case ASTVEBX: /* stvebx, stvehx, stvewx, stvx, stvxl */
			opset(ASTVEHX, r0)
			opset(ASTVEWX, r0)
			opset(ASTVX, r0)
			opset(ASTVXL, r0)

		case AVAND: /* vand, vandc, vnand */
			opset(AVAND, r0)
			opset(AVANDC, r0)
			opset(AVNAND, r0)

		case AVMRGOW: /* vmrgew, vmrgow */
			opset(AVMRGEW, r0)

		case AVOR: /* vor, vorc, vxor, vnor, veqv */
			opset(AVOR, r0)
			opset(AVORC, r0)
			opset(AVXOR, r0)
			opset(AVNOR, r0)
			opset(AVEQV, r0)

		case AVADDUM: /* vaddubm, vadduhm, vadduwm, vaddudm, vadduqm */
			opset(AVADDUBM, r0)
			opset(AVADDUHM, r0)
			opset(AVADDUWM, r0)
			opset(AVADDUDM, r0)
			opset(AVADDUQM, r0)

		case AVADDCU: /* vaddcuq, vaddcuw */
			opset(AVADDCUQ, r0)
			opset(AVADDCUW, r0)

		case AVADDUS: /* vaddubs, vadduhs, vadduws */
			opset(AVADDUBS, r0)
			opset(AVADDUHS, r0)
			opset(AVADDUWS, r0)

		case AVADDSS: /* vaddsbs, vaddshs, vaddsws */
			opset(AVADDSBS, r0)
			opset(AVADDSHS, r0)
			opset(AVADDSWS, r0)

		case AVADDE: /* vaddeuqm, vaddecuq */
			opset(AVADDEUQM, r0)
			opset(AVADDECUQ, r0)

		case AVSUBUM: /* vsububm, vsubuhm, vsubuwm, vsubudm, vsubuqm */
			opset(AVSUBUBM, r0)
			opset(AVSUBUHM, r0)
			opset(AVSUBUWM, r0)
			opset(AVSUBUDM, r0)
			opset(AVSUBUQM, r0)

		case AVSUBCU: /* vsubcuq, vsubcuw */
			opset(AVSUBCUQ, r0)
			opset(AVSUBCUW, r0)

		case AVSUBUS: /* vsububs, vsubuhs, vsubuws */
			opset(AVSUBUBS, r0)
			opset(AVSUBUHS, r0)
			opset(AVSUBUWS, r0)

		case AVSUBSS: /* vsubsbs, vsubshs, vsubsws */
			opset(AVSUBSBS, r0)
			opset(AVSUBSHS, r0)
			opset(AVSUBSWS, r0)

		case AVSUBE: /* vsubeuqm, vsubecuq */
			opset(AVSUBEUQM, r0)
			opset(AVSUBECUQ, r0)

		case AVMULESB: /* vmulesb, vmulosb, vmuleub, vmuloub, vmulosh, vmulouh, vmulesw, vmulosw, vmuleuw, vmulouw, vmuluwm */
			opset(AVMULOSB, r0)
			opset(AVMULEUB, r0)
			opset(AVMULOUB, r0)
			opset(AVMULESH, r0)
			opset(AVMULOSH, r0)
			opset(AVMULEUH, r0)
			opset(AVMULOUH, r0)
			opset(AVMULESW, r0)
			opset(AVMULOSW, r0)
			opset(AVMULEUW, r0)
			opset(AVMULOUW, r0)
			opset(AVMULUWM, r0)
		case AVPMSUM: /* vpmsumb, vpmsumh, vpmsumw, vpmsumd */
			opset(AVPMSUMB, r0)
			opset(AVPMSUMH, r0)
			opset(AVPMSUMW, r0)
			opset(AVPMSUMD, r0)

		case AVR: /* vrlb, vrlh, vrlw, vrld */
			opset(AVRLB, r0)
			opset(AVRLH, r0)
			opset(AVRLW, r0)
			opset(AVRLD, r0)

		case AVS: /* vs[l,r], vs[l,r]o, vs[l,r]b, vs[l,r]h, vs[l,r]w, vs[l,r]d */
			opset(AVSLB, r0)
			opset(AVSLH, r0)
			opset(AVSLW, r0)
			opset(AVSL, r0)
			opset(AVSLO, r0)
			opset(AVSRB, r0)
			opset(AVSRH, r0)
			opset(AVSRW, r0)
			opset(AVSR, r0)
			opset(AVSRO, r0)
			opset(AVSLD, r0)
			opset(AVSRD, r0)

		case AVSA: /* vsrab, vsrah, vsraw, vsrad */
			opset(AVSRAB, r0)
			opset(AVSRAH, r0)
			opset(AVSRAW, r0)
			opset(AVSRAD, r0)

		case AVSOI: /* vsldoi */
			opset(AVSLDOI, r0)

		case AVCLZ: /* vclzb, vclzh, vclzw, vclzd */
			opset(AVCLZB, r0)
			opset(AVCLZH, r0)
			opset(AVCLZW, r0)
			opset(AVCLZD, r0)

		case AVPOPCNT: /* vpopcntb, vpopcnth, vpopcntw, vpopcntd */
			opset(AVPOPCNTB, r0)
			opset(AVPOPCNTH, r0)
			opset(AVPOPCNTW, r0)
			opset(AVPOPCNTD, r0)

		case AVCMPEQ: /* vcmpequb[.], vcmpequh[.], vcmpequw[.], vcmpequd[.] */
			opset(AVCMPEQUB, r0)
			opset(AVCMPEQUBCC, r0)
			opset(AVCMPEQUH, r0)
			opset(AVCMPEQUHCC, r0)
			opset(AVCMPEQUW, r0)
			opset(AVCMPEQUWCC, r0)
			opset(AVCMPEQUD, r0)
			opset(AVCMPEQUDCC, r0)

		case AVCMPGT: /* vcmpgt[u,s]b[.], vcmpgt[u,s]h[.], vcmpgt[u,s]w[.], vcmpgt[u,s]d[.] */
			opset(AVCMPGTUB, r0)
			opset(AVCMPGTUBCC, r0)
			opset(AVCMPGTUH, r0)
			opset(AVCMPGTUHCC, r0)
			opset(AVCMPGTUW, r0)
			opset(AVCMPGTUWCC, r0)
			opset(AVCMPGTUD, r0)
			opset(AVCMPGTUDCC, r0)
			opset(AVCMPGTSB, r0)
			opset(AVCMPGTSBCC, r0)
			opset(AVCMPGTSH, r0)
			opset(AVCMPGTSHCC, r0)
			opset(AVCMPGTSW, r0)
			opset(AVCMPGTSWCC, r0)
			opset(AVCMPGTSD, r0)
			opset(AVCMPGTSDCC, r0)

		case AVCMPNEZB: /* vcmpnezb[.] */
			opset(AVCMPNEZBCC, r0)
			opset(AVCMPNEB, r0)
			opset(AVCMPNEBCC, r0)
			opset(AVCMPNEH, r0)
			opset(AVCMPNEHCC, r0)
			opset(AVCMPNEW, r0)
			opset(AVCMPNEWCC, r0)

		case AVPERM: /* vperm */
			opset(AVPERMXOR, r0)
			opset(AVPERMR, r0)

		case AVBPERMQ: /* vbpermq, vbpermd */
			opset(AVBPERMD, r0)

		case AVSEL: /* vsel */
			opset(AVSEL, r0)

		case AVSPLTB: /* vspltb, vsplth, vspltw */
			opset(AVSPLTH, r0)
			opset(AVSPLTW, r0)

		case AVSPLTISB: /* vspltisb, vspltish, vspltisw */
			opset(AVSPLTISH, r0)
			opset(AVSPLTISW, r0)

		case AVCIPH: /* vcipher, vcipherlast */
			opset(AVCIPHER, r0)
			opset(AVCIPHERLAST, r0)

		case AVNCIPH: /* vncipher, vncipherlast */
			opset(AVNCIPHER, r0)
			opset(AVNCIPHERLAST, r0)

		case AVSBOX: /* vsbox */
			opset(AVSBOX, r0)

		case AVSHASIGMA: /* vshasigmaw, vshasigmad */
			opset(AVSHASIGMAW, r0)
			opset(AVSHASIGMAD, r0)

		case ALXVD2X: /* lxvd2x, lxvdsx, lxvw4x, lxvh8x, lxvb16x */
			opset(ALXVDSX, r0)
			opset(ALXVW4X, r0)
			opset(ALXVH8X, r0)
			opset(ALXVB16X, r0)

		case ALXV: /* lxv */
			opset(ALXV, r0)

		case ALXVL: /* lxvl, lxvll, lxvx */
			opset(ALXVLL, r0)
			opset(ALXVX, r0)

		case ASTXVD2X: /* stxvd2x, stxvdsx, stxvw4x, stxvh8x, stxvb16x */
			opset(ASTXVW4X, r0)
			opset(ASTXVH8X, r0)
			opset(ASTXVB16X, r0)

		case ASTXV: /* stxv */
			opset(ASTXV, r0)

		case ASTXVL: /* stxvl, stxvll, stvx */
			opset(ASTXVLL, r0)
			opset(ASTXVX, r0)

		case ALXSDX: /* lxsdx  */
			opset(ALXSDX, r0)

		case ASTXSDX: /* stxsdx */
			opset(ASTXSDX, r0)

		case ALXSIWAX: /* lxsiwax, lxsiwzx  */
			opset(ALXSIWZX, r0)

		case ASTXSIWX: /* stxsiwx */
			opset(ASTXSIWX, r0)

		case AMFVSRD: /* mfvsrd, mfvsrwz (and extended mnemonics), mfvsrld */
			opset(AMFFPRD, r0)
			opset(AMFVRD, r0)
			opset(AMFVSRWZ, r0)
			opset(AMFVSRLD, r0)

		case AMTVSRD: /* mtvsrd, mtvsrwa, mtvsrwz (and extended mnemonics), mtvsrdd, mtvsrws */
			opset(AMTFPRD, r0)
			opset(AMTVRD, r0)
			opset(AMTVSRWA, r0)
			opset(AMTVSRWZ, r0)
			opset(AMTVSRWS, r0)

		case AXXLAND:
			opset(AXXLANDC, r0)
			opset(AXXLEQV, r0)
			opset(AXXLNAND, r0)
			opset(AXXLORC, r0)
			opset(AXXLNOR, r0)
			opset(AXXLORQ, r0)
			opset(AXXLXOR, r0)
			opset(AXXLOR, r0)
			opset(AXSMAXJDP, r0)
			opset(AXSMINJDP, r0)

		case AXXSEL: /* xxsel */
			opset(AXXSEL, r0)

		case AXXMRGHW: /* xxmrghw, xxmrglw */
			opset(AXXMRGLW, r0)

		case AXXSPLTW: /* xxspltw */
			opset(AXXSPLTW, r0)

		case AXXSPLTIB: /* xxspltib */
			opset(AXXSPLTIB, r0)

		case AXXPERM: /* xxpermdi */
			opset(AXXPERM, r0)

		case AXXSLDWI: /* xxsldwi */
			opset(AXXPERMDI, r0)
			opset(AXXSLDWI, r0)

		case AXXBRQ: /* xxbrq, xxbrd, xxbrw, xxbrh */
			opset(AXXBRD, r0)
			opset(AXXBRW, r0)
			opset(AXXBRH, r0)

		case AXSCVDPSP: /* xscvdpsp, xscvspdp, xscvdpspn, xscvspdpn */
			opset(AXSCVSPDP, r0)
			opset(AXSCVDPSPN, r0)
			opset(AXSCVSPDPN, r0)

		case AXVCVDPSP: /* xvcvdpsp, xvcvspdp */
			opset(AXVCVSPDP, r0)

		case AXSCVDPSXDS: /* xscvdpsxds, xscvdpsxws, xscvdpuxds, xscvdpuxws */
			opset(AXSCVDPSXWS, r0)
			opset(AXSCVDPUXDS, r0)
			opset(AXSCVDPUXWS, r0)

		case AXSCVSXDDP: /* xscvsxddp, xscvuxddp, xscvsxdsp, xscvuxdsp */
			opset(AXSCVUXDDP, r0)
			opset(AXSCVSXDSP, r0)
			opset(AXSCVUXDSP, r0)

		case AXVCVDPSXDS: /* xvcvdpsxds, xvcvdpsxws, xvcvdpuxds, xvcvdpuxws, xvcvspsxds, xvcvspsxws, xvcvspuxds, xvcvspuxws */
			opset(AXVCVDPSXDS, r0)
			opset(AXVCVDPSXWS, r0)
			opset(AXVCVDPUXDS, r0)
			opset(AXVCVDPUXWS, r0)
			opset(AXVCVSPSXDS, r0)
			opset(AXVCVSPSXWS, r0)
			opset(AXVCVSPUXDS, r0)
			opset(AXVCVSPUXWS, r0)

		case AXVCVSXDDP: /* xvcvsxddp, xvcvsxwdp, xvcvuxddp, xvcvuxwdp, xvcvsxdsp, xvcvsxwsp, xvcvuxdsp, xvcvuxwsp */
			opset(AXVCVSXWDP, r0)
			opset(AXVCVUXDDP, r0)
			opset(AXVCVUXWDP, r0)
			opset(AXVCVSXDSP, r0)
			opset(AXVCVSXWSP, r0)
			opset(AXVCVUXDSP, r0)
			opset(AXVCVUXWSP, r0)

		case AAND: /* logical op Rb,Rs,Ra; no literal */
			opset(AANDN, r0)
			opset(AANDNCC, r0)
			opset(AEQV, r0)
			opset(AEQVCC, r0)
			opset(ANAND, r0)
			opset(ANANDCC, r0)
			opset(ANOR, r0)
			opset(ANORCC, r0)
			opset(AORCC, r0)
			opset(AORN, r0)
			opset(AORNCC, r0)
			opset(AXORCC, r0)

		case AADDME: /* op Ra, Rd */
			opset(AADDMECC, r0)

			opset(AADDMEV, r0)
			opset(AADDMEVCC, r0)
			opset(AADDZE, r0)
			opset(AADDZECC, r0)
			opset(AADDZEV, r0)
			opset(AADDZEVCC, r0)
			opset(ASUBME, r0)
			opset(ASUBMECC, r0)
			opset(ASUBMEV, r0)
			opset(ASUBMEVCC, r0)
			opset(ASUBZE, r0)
			opset(ASUBZECC, r0)
			opset(ASUBZEV, r0)
			opset(ASUBZEVCC, r0)

		case AADDC:
			opset(AADDCCC, r0)

		case ABEQ:
			opset(ABGE, r0)
			opset(ABGT, r0)
			opset(ABLE, r0)
			opset(ABLT, r0)
			opset(ABNE, r0)
			opset(ABVC, r0)
			opset(ABVS, r0)

		case ABR:
			opset(ABL, r0)

		case ABC:
			opset(ABCL, r0)

		case ABDNZ:
			opset(ABDZ, r0)

		case AEXTSB: /* op Rs, Ra */
			opset(AEXTSBCC, r0)

			opset(AEXTSH, r0)
			opset(AEXTSHCC, r0)
			opset(ACNTLZW, r0)
			opset(ACNTLZWCC, r0)
			opset(ACNTLZD, r0)
			opset(AEXTSW, r0)
			opset(AEXTSWCC, r0)
			opset(ACNTLZDCC, r0)

		case AFABS: /* fop [s,]d */
			opset(AFABSCC, r0)

			opset(AFNABS, r0)
			opset(AFNABSCC, r0)
			opset(AFNEG, r0)
			opset(AFNEGCC, r0)
			opset(AFRSP, r0)
			opset(AFRSPCC, r0)
			opset(AFCTIW, r0)
			opset(AFCTIWCC, r0)
			opset(AFCTIWZ, r0)
			opset(AFCTIWZCC, r0)
			opset(AFCTID, r0)
			opset(AFCTIDCC, r0)
			opset(AFCTIDZ, r0)
			opset(AFCTIDZCC, r0)
			opset(AFCFID, r0)
			opset(AFCFIDCC, r0)
			opset(AFCFIDU, r0)
			opset(AFCFIDUCC, r0)
			opset(AFCFIDS, r0)
			opset(AFCFIDSCC, r0)
			opset(AFRES, r0)
			opset(AFRESCC, r0)
			opset(AFRIM, r0)
			opset(AFRIMCC, r0)
			opset(AFRIP, r0)
			opset(AFRIPCC, r0)
			opset(AFRIZ, r0)
			opset(AFRIZCC, r0)
			opset(AFRIN, r0)
			opset(AFRINCC, r0)
			opset(AFRSQRTE, r0)
			opset(AFRSQRTECC, r0)
			opset(AFSQRT, r0)
			opset(AFSQRTCC, r0)
			opset(AFSQRTS, r0)
			opset(AFSQRTSCC, r0)

		case AFADD:
			opset(AFADDS, r0)
			opset(AFADDCC, r0)
			opset(AFADDSCC, r0)
			opset(AFCPSGN, r0)
			opset(AFCPSGNCC, r0)
			opset(AFDIV, r0)
			opset(AFDIVS, r0)
			opset(AFDIVCC, r0)
			opset(AFDIVSCC, r0)
			opset(AFSUB, r0)
			opset(AFSUBS, r0)
			opset(AFSUBCC, r0)
			opset(AFSUBSCC, r0)
			opset(ADADD, r0)
			opset(ADDIV, r0)
			opset(ADSUB, r0)

		case ADADDQ:
			opset(ADDIVQ, r0)
			opset(ADSUBQ, r0)

		case AFMADD:
			opset(AFMADDCC, r0)
			opset(AFMADDS, r0)
			opset(AFMADDSCC, r0)
			opset(AFMSUB, r0)
			opset(AFMSUBCC, r0)
			opset(AFMSUBS, r0)
			opset(AFMSUBSCC, r0)
			opset(AFNMADD, r0)
			opset(AFNMADDCC, r0)
			opset(AFNMADDS, r0)
			opset(AFNMADDSCC, r0)
			opset(AFNMSUB, r0)
			opset(AFNMSUBCC, r0)
			opset(AFNMSUBS, r0)
			opset(AFNMSUBSCC, r0)
			opset(AFSEL, r0)
			opset(AFSELCC, r0)

		case AFMUL:
			opset(AFMULS, r0)
			opset(AFMULCC, r0)
			opset(AFMULSCC, r0)
			opset(ADMUL, r0)

		case ADMULQ:
			opset(ADMULQ, r0)

		case AFCMPO:
			opset(AFCMPU, r0)
			opset(ADCMPU, r0)
			opset(ADCMPO, r0)

		case ADCMPOQ:
			opset(ADCMPUQ, r0)

		case AMTFSB0:
			opset(AMTFSB0CC, r0)
			opset(AMTFSB1, r0)
			opset(AMTFSB1CC, r0)

		case ANEG: /* op [Ra,] Rd */
			opset(ANEGCC, r0)

			opset(ANEGV, r0)
			opset(ANEGVCC, r0)

		case AOR: /* or/xor Rb,Rs,Ra; ori/xori $uimm,Rs,R */
			opset(AXOR, r0)

		case AORIS: /* oris/xoris $uimm,Rs,Ra */
			opset(AXORIS, r0)

		case ASLW:
			opset(ASLWCC, r0)
			opset(ASRW, r0)
			opset(ASRWCC, r0)
			opset(AROTLW, r0)

		case ASLD:
			opset(ASLDCC, r0)
			opset(ASRD, r0)
			opset(ASRDCC, r0)
			opset(AROTL, r0)

		case ASRAW: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
			opset(ASRAWCC, r0)

		case AEXTSWSLI:
			opset(AEXTSWSLICC, r0)

		case ASRAD: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
			opset(ASRADCC, r0)

		case ASUB: /* SUB Ra,Rb,Rd => subf Rd,ra,rb */
			opset(ASUB, r0)

			opset(ASUBCC, r0)
			opset(ASUBV, r0)
			opset(ASUBVCC, r0)
			opset(ASUBCCC, r0)
			opset(ASUBCV, r0)
			opset(ASUBCVCC, r0)
			opset(ASUBE, r0)
			opset(ASUBECC, r0)
			opset(ASUBEV, r0)
			opset(ASUBEVCC, r0)

		case ASYNC:
			opset(AISYNC, r0)
			opset(ALWSYNC, r0)
			opset(APTESYNC, r0)
			opset(ATLBSYNC, r0)

		case ARLWNM:
			opset(ARLWNMCC, r0)
			opset(ARLWMI, r0)
			opset(ARLWMICC, r0)

		case ARLDMI:
			opset(ARLDMICC, r0)
			opset(ARLDIMI, r0)
			opset(ARLDIMICC, r0)

		case ARLDC:
			opset(ARLDCCC, r0)

		case ARLDCL:
			opset(ARLDCR, r0)
			opset(ARLDCLCC, r0)
			opset(ARLDCRCC, r0)

		case ARLDICL:
			opset(ARLDICLCC, r0)
			opset(ARLDICR, r0)
			opset(ARLDICRCC, r0)
			opset(ARLDIC, r0)
			opset(ARLDICCC, r0)
			opset(ACLRLSLDI, r0)

		case AFMOVD:
			opset(AFMOVDCC, r0)
			opset(AFMOVDU, r0)
			opset(AFMOVS, r0)
			opset(AFMOVSU, r0)

		case ALDAR:
			opset(ALBAR, r0)
			opset(ALHAR, r0)
			opset(ALWAR, r0)

		case ASYSCALL: /* just the op; flow of control */
			opset(ARFI, r0)

			opset(ARFCI, r0)
			opset(ARFID, r0)
			opset(AHRFID, r0)

		case AMOVHBR:
			opset(AMOVWBR, r0)
			opset(AMOVDBR, r0)

		case ASLBMFEE:
			opset(ASLBMFEV, r0)

		case ATW:
			opset(ATD, r0)

		case ATLBIE:
			opset(ASLBIE, r0)
			opset(ATLBIEL, r0)

		case AEIEIO:
			opset(ASLBIA, r0)

		case ACMP:
			opset(ACMPW, r0)

		case ACMPU:
			opset(ACMPWU, r0)

		case ACMPB:
			opset(ACMPB, r0)

		case AFTDIV:
			opset(AFTDIV, r0)

		case AFTSQRT:
			opset(AFTSQRT, r0)

		case AMOVW: /* load/store/move word with sign extension; move 32-bit literals  */
			opset(AMOVWZ, r0) /* Same as above, but zero extended */

		case AVCLZLSBB:
			opset(AVCTZLSBB, r0)

		case AADD,
			AADDIS,
			AANDCC, /* and. Rb,Rs,Ra; andi. $uimm,Rs,Ra */
			AANDISCC,
			AFMOVSX,
			AFMOVSZ,
			ALSW,
			AMOVD,  /* load/store/move 64-bit values, including 32-bit literals with/without sign-extension */
			AMOVB,  /* macro: move byte with sign extension */
			AMOVBU, /* macro: move byte with sign extension & update */
			AMOVFL,
			/* op $s[,r2],r3; op r1[,r2],r3; no cc/v */
			ASUBC, /* op r1,$s,r3; op r1[,r2],r3 */
			ASTSW,
			ASLBMTE,
			AWORD,
			ADWORD,
			ADARN,
			AVMSUMUDM,
			AADDEX,
			ACMPEQB,
			ACLRLSLWI,
			AMTVSRDD,
			APNOP,
			AISEL,
			ASETB,
			obj.ANOP,
			obj.ATEXT,
			obj.AUNDEF,
			obj.AFUNCDATA,
			obj.APCALIGN,
			obj.APCDATA,
			obj.ADUFFZERO,
			obj.ADUFFCOPY:
			break
		}
	}
}

func OPVXX1(o uint32, xo uint32, oe uint32) uint32 {
	return o<<26 | xo<<1 | oe<<11
}

func OPVXX2(o uint32, xo uint32, oe uint32) uint32 {
	return o<<26 | xo<<2 | oe<<11
}

func OPVXX2VA(o uint32, xo uint32, oe uint32) uint32 {
	return o<<26 | xo<<2 | oe<<16
}

func OPVXX3(o uint32, xo uint32, oe uint32) uint32 {
	return o<<26 | xo<<3 | oe<<11
}

func OPVXX4(o uint32, xo uint32, oe uint32) uint32 {
	return o<<26 | xo<<4 | oe<<11
}

func OPDQ(o uint32, xo uint32, oe uint32) uint32 {
	return o<<26 | xo | oe<<4
}

func OPVX(o uint32, xo uint32, oe uint32, rc uint32) uint32 {
	return o<<26 | xo | oe<<11 | rc&1
}

func OPVC(o uint32, xo uint32, oe uint32, rc uint32) uint32 {
	return o<<26 | xo | oe<<11 | (rc&1)<<10
}

func OPVCC(o uint32, xo uint32, oe uint32, rc uint32) uint32 {
	return o<<26 | xo<<1 | oe<<10 | rc&1
}

/* Generate MD-form opcode */
func OPMD(o, xo, rc uint32) uint32 {
	return o<<26 | xo<<2 | rc&1
}

/* the order is dest, a/s, b/imm for both arithmetic and logical operations. */
func AOP_RRR(op uint32, d uint32, a uint32, b uint32) uint32 {
	return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11
}

/* VX-form 2-register operands, r/none/r */
func AOP_RR(op uint32, d uint32, a uint32) uint32 {
	return op | (d&31)<<21 | (a&31)<<11
}

/* VA-form 4-register operands */
func AOP_RRRR(op uint32, d uint32, a uint32, b uint32, c uint32) uint32 {
	return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11 | (c&31)<<6
}

func AOP_IRR(op uint32, d uint32, a uint32, simm uint32) uint32 {
	return op | (d&31)<<21 | (a&31)<<16 | simm&0xFFFF
}

/* VX-form 2-register + UIM operands */
func AOP_VIRR(op uint32, d uint32, a uint32, simm uint32) uint32 {
	return op | (d&31)<<21 | (simm&0xFFFF)<<16 | (a&31)<<11
}

/* VX-form 2-register + ST + SIX operands */
func AOP_IIRR(op uint32, d uint32, a uint32, sbit uint32, simm uint32) uint32 {
	return op | (d&31)<<21 | (a&31)<<16 | (sbit&1)<<15 | (simm&0xF)<<11
}

/* VA-form 3-register + SHB operands */
func AOP_IRRR(op uint32, d uint32, a uint32, b uint32, simm uint32) uint32 {
	return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11 | (simm&0xF)<<6
}

/* VX-form 1-register + SIM operands */
func AOP_IR(op uint32, d uint32, simm uint32) uint32 {
	return op | (d&31)<<21 | (simm&31)<<16
}

/* XX1-form 3-register operands, 1 VSR operand */
func AOP_XX1(op uint32, r uint32, a uint32, b uint32) uint32 {
	return op | (r&31)<<21 | (a&31)<<16 | (b&31)<<11 | (r&32)>>5
}

/* XX2-form 3-register operands, 2 VSR operands */
func AOP_XX2(op uint32, xt uint32, a uint32, xb uint32) uint32 {
	return op | (xt&31)<<21 | (a&3)<<16 | (xb&31)<<11 | (xb&32)>>4 | (xt&32)>>5
}

/* XX3-form 3 VSR operands */
func AOP_XX3(op uint32, xt uint32, xa uint32, xb uint32) uint32 {
	return op | (xt&31)<<21 | (xa&31)<<16 | (xb&31)<<11 | (xa&32)>>3 | (xb&32)>>4 | (xt&32)>>5
}

/* XX3-form 3 VSR operands + immediate */
func AOP_XX3I(op uint32, xt uint32, xa uint32, xb uint32, c uint32) uint32 {
	return op | (xt&31)<<21 | (xa&31)<<16 | (xb&31)<<11 | (c&3)<<8 | (xa&32)>>3 | (xb&32)>>4 | (xt&32)>>5
}

/* XX4-form, 4 VSR operands */
func AOP_XX4(op uint32, xt uint32, xa uint32, xb uint32, xc uint32) uint32 {
	return op | (xt&31)<<21 | (xa&31)<<16 | (xb&31)<<11 | (xc&31)<<6 | (xc&32)>>2 | (xa&32)>>3 | (xb&32)>>4 | (xt&32)>>5
}

/* DQ-form, VSR register, register + offset operands */
func AOP_DQ(op uint32, xt uint32, a uint32, b uint32) uint32 {
	/* The EA for this instruction form is (RA) + DQ << 4, where DQ is a 12-bit signed integer. */
	/* In order to match the output of the GNU objdump (and make the usage in Go asm easier), the */
	/* instruction is called using the sign extended value (i.e. a valid offset would be -32752 or 32752, */
	/* not -2047 or 2047), so 'b' needs to be adjusted to the expected 12-bit DQ value. Bear in mind that */
	/* bits 0 to 3 in 'dq' need to be zero, otherwise this will generate an illegal instruction. */
	/* If in doubt how this instruction form is encoded, refer to ISA 3.0b, pages 492 and 507. */
	dq := b >> 4
	return op | (xt&31)<<21 | (a&31)<<16 | (dq&4095)<<4 | (xt&32)>>2
}

/* Z23-form, 3-register operands + CY field */
func AOP_Z23I(op uint32, d uint32, a uint32, b uint32, c uint32) uint32 {
	return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11 | (c&3)<<9
}

/* X-form, 3-register operands + EH field */
func AOP_RRRI(op uint32, d uint32, a uint32, b uint32, c uint32) uint32 {
	return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11 | (c & 1)
}

func LOP_RRR(op uint32, a uint32, s uint32, b uint32) uint32 {
	return op | (s&31)<<21 | (a&31)<<16 | (b&31)<<11
}

func LOP_IRR(op uint32, a uint32, s uint32, uimm uint32) uint32 {
	return op | (s&31)<<21 | (a&31)<<16 | uimm&0xFFFF
}

func OP_BR(op uint32, li uint32, aa uint32) uint32 {
	return op | li&0x03FFFFFC | aa<<1
}

func OP_BC(op uint32, bo uint32, bi uint32, bd uint32, aa uint32) uint32 {
	return op | (bo&0x1F)<<21 | (bi&0x1F)<<16 | bd&0xFFFC | aa<<1
}

func OP_BCR(op uint32, bo uint32, bi uint32) uint32 {
	return op | (bo&0x1F)<<21 | (bi&0x1F)<<16
}

func OP_RLW(op uint32, a uint32, s uint32, sh uint32, mb uint32, me uint32) uint32 {
	return op | (s&31)<<21 | (a&31)<<16 | (sh&31)<<11 | (mb&31)<<6 | (me&31)<<1
}

func AOP_EXTSWSLI(op uint32, a uint32, s uint32, sh uint32) uint32 {
	return op | (a&31)<<21 | (s&31)<<16 | (sh&31)<<11 | ((sh&32)>>5)<<1
}

func AOP_ISEL(op uint32, t uint32, a uint32, b uint32, bc uint32) uint32 {
	return op | (t&31)<<21 | (a&31)<<16 | (b&31)<<11 | (bc&0x1F)<<6
}

/* MD-form 2-register, 2 6-bit immediate operands */
func AOP_MD(op uint32, a uint32, s uint32, sh uint32, m uint32) uint32 {
	return op | (s&31)<<21 | (a&31)<<16 | (sh&31)<<11 | ((sh&32)>>5)<<1 | (m&31)<<6 | ((m&32)>>5)<<5
}

/* MDS-form 3-register, 1 6-bit immediate operands. rsh argument is a register. */
func AOP_MDS(op, to, from, rsh, m uint32) uint32 {
	return AOP_MD(op, to, from, rsh&31, m)
}

func AOP_PFX_00_8LS(r, ie uint32) uint32 {
	return 1<<26 | 0<<24 | 0<<23 | (r&1)<<20 | (ie & 0x3FFFF)
}
func AOP_PFX_10_MLS(r, ie uint32) uint32 {
	return 1<<26 | 2<<24 | 0<<23 | (r&1)<<20 | (ie & 0x3FFFF)
}

const (
	/* each rhs is OPVCC(_, _, _, _) */
	OP_ADD      = 31<<26 | 266<<1 | 0<<10 | 0
	OP_ADDI     = 14<<26 | 0<<1 | 0<<10 | 0
	OP_ADDIS    = 15<<26 | 0<<1 | 0<<10 | 0
	OP_ANDI     = 28<<26 | 0<<1 | 0<<10 | 0
	OP_EXTSB    = 31<<26 | 954<<1 | 0<<10 | 0
	OP_EXTSH    = 31<<26 | 922<<1 | 0<<10 | 0
	OP_EXTSW    = 31<<26 | 986<<1 | 0<<10 | 0
	OP_ISEL     = 31<<26 | 15<<1 | 0<<10 | 0
	OP_MCRF     = 19<<26 | 0<<1 | 0<<10 | 0
	OP_MCRFS    = 63<<26 | 64<<1 | 0<<10 | 0
	OP_MCRXR    = 31<<26 | 512<<1 | 0<<10 | 0
	OP_MFCR     = 31<<26 | 19<<1 | 0<<10 | 0
	OP_MFFS     = 63<<26 | 583<<1 | 0<<10 | 0
	OP_MFSPR    = 31<<26 | 339<<1 | 0<<10 | 0
	OP_MFSR     = 31<<26 | 595<<1 | 0<<10 | 0
	OP_MFSRIN   = 31<<26 | 659<<1 | 0<<10 | 0
	OP_MTCRF    = 31<<26 | 144<<1 | 0<<10 | 0
	OP_MTFSF    = 63<<26 | 711<<1 | 0<<10 | 0
	OP_MTFSFI   = 63<<26 | 134<<1 | 0<<10 | 0
	OP_MTSPR    = 31<<26 | 467<<1 | 0<<10 | 0
	OP_MTSR     = 31<<26 | 210<<1 | 0<<10 | 0
	OP_MTSRIN   = 31<<26 | 242<<1 | 0<<10 | 0
	OP_MULLW    = 31<<26 | 235<<1 | 0<<10 | 0
	OP_MULLD    = 31<<26 | 233<<1 | 0<<10 | 0
	OP_OR       = 31<<26 | 444<<1 | 0<<10 | 0
	OP_ORI      = 24<<26 | 0<<1 | 0<<10 | 0
	OP_ORIS     = 25<<26 | 0<<1 | 0<<10 | 0
	OP_XORI     = 26<<26 | 0<<1 | 0<<10 | 0
	OP_XORIS    = 27<<26 | 0<<1 | 0<<10 | 0
	OP_RLWINM   = 21<<26 | 0<<1 | 0<<10 | 0
	OP_RLWNM    = 23<<26 | 0<<1 | 0<<10 | 0
	OP_SUBF     = 31<<26 | 40<<1 | 0<<10 | 0
	OP_RLDIC    = 30<<26 | 4<<1 | 0<<10 | 0
	OP_RLDICR   = 30<<26 | 2<<1 | 0<<10 | 0
	OP_RLDICL   = 30<<26 | 0<<1 | 0<<10 | 0
	OP_RLDCL    = 30<<26 | 8<<1 | 0<<10 | 0
	OP_EXTSWSLI = 31<<26 | 445<<2
	OP_SETB     = 31<<26 | 128<<1
)

func pfxadd(rt, ra int16, r uint32, imm32 int64) (uint32, uint32) {
	return AOP_PFX_10_MLS(r, uint32(imm32>>16)), AOP_IRR(14<<26, uint32(rt), uint32(ra), uint32(imm32))
}

func pfxload(a obj.As, reg int16, base int16, r uint32) (uint32, uint32) {
	switch a {
	case AMOVH:
		return AOP_PFX_10_MLS(r, 0), AOP_IRR(42<<26, uint32(reg), uint32(base), 0)
	case AMOVW:
		return AOP_PFX_00_8LS(r, 0), AOP_IRR(41<<26, uint32(reg), uint32(base), 0)
	case AMOVD:
		return AOP_PFX_00_8LS(r, 0), AOP_IRR(57<<26, uint32(reg), uint32(base), 0)
	case AMOVBZ, AMOVB:
		return AOP_PFX_10_MLS(r, 0), AOP_IRR(34<<26, uint32(reg), uint32(base), 0)
	case AMOVHZ:
		return AOP_PFX_10_MLS(r, 0), AOP_IRR(40<<26, uint32(reg), uint32(base), 0)
	case AMOVWZ:
		return AOP_PFX_10_MLS(r, 0), AOP_IRR(32<<26, uint32(reg), uint32(base), 0)
	case AFMOVS:
		return AOP_PFX_10_MLS(r, 0), AOP_IRR(48<<26, uint32(reg), uint32(base), 0)
	case AFMOVD:
		return AOP_PFX_10_MLS(r, 0), AOP_IRR(50<<26, uint32(reg), uint32(base), 0)
	}
	log.Fatalf("Error no pfxload for %v\n", a)
	return 0, 0
}

func pfxstore(a obj.As, reg int16, base int16, r uint32) (uint32, uint32) {
	switch a {
	case AMOVD:
		return AOP_PFX_00_8LS(r, 0), AOP_IRR(61<<26, uint32(reg), uint32(base), 0)
	case AMOVBZ, AMOVB:
		return AOP_PFX_10_MLS(r, 0), AOP_IRR(38<<26, uint32(reg), uint32(base), 0)
	case AMOVHZ, AMOVH:
		return AOP_PFX_10_MLS(r, 0), AOP_IRR(44<<26, uint32(reg), uint32(base), 0)
	case AMOVWZ, AMOVW:
		return AOP_PFX_10_MLS(r, 0), AOP_IRR(36<<26, uint32(reg), uint32(base), 0)
	case AFMOVS:
		return AOP_PFX_10_MLS(r, 0), AOP_IRR(52<<26, uint32(reg), uint32(base), 0)
	case AFMOVD:
		return AOP_PFX_10_MLS(r, 0), AOP_IRR(54<<26, uint32(reg), uint32(base), 0)
	}
	log.Fatalf("Error no pfxstore for %v\n", a)
	return 0, 0
}

func oclass(a *obj.Addr) int {
	return int(a.Class) - 1
}

const (
	D_FORM = iota
	DS_FORM
)

// This function determines when a non-indexed load or store is D or
// DS form for use in finding the size of the offset field in the instruction.
// The size is needed when setting the offset value in the instruction
// and when generating relocation for that field.
// DS form instructions include: ld, ldu, lwa, std, stdu.  All other
// loads and stores with an offset field are D form.  This function should
// only be called with the same opcodes as are handled by opstore and opload.
func (c *ctxt9) opform(insn uint32) int {
	switch insn {
	default:
		c.ctxt.Diag("bad insn in loadform: %x", insn)
	case OPVCC(58, 0, 0, 0), // ld
		OPVCC(58, 0, 0, 1),        // ldu
		OPVCC(58, 0, 0, 0) | 1<<1, // lwa
		OPVCC(62, 0, 0, 0),        // std
		OPVCC(62, 0, 0, 1):        //stdu
		return DS_FORM
	case OP_ADDI, // add
		OPVCC(32, 0, 0, 0), // lwz
		OPVCC(33, 0, 0, 0), // lwzu
		OPVCC(34, 0, 0, 0), // lbz
		OPVCC(35, 0, 0, 0), // lbzu
		OPVCC(40, 0, 0, 0), // lhz
		OPVCC(41, 0, 0, 0), // lhzu
		OPVCC(42, 0, 0, 0), // lha
		OPVCC(43, 0, 0, 0), // lhau
		OPVCC(46, 0, 0, 0), // lmw
		OPVCC(48, 0, 0, 0), // lfs
		OPVCC(49, 0, 0, 0), // lfsu
		OPVCC(50, 0, 0, 0), // lfd
		OPVCC(51, 0, 0, 0), // lfdu
		OPVCC(36, 0, 0, 0), // stw
		OPVCC(37, 0, 0, 0), // stwu
		OPVCC(38, 0, 0, 0), // stb
		OPVCC(39, 0, 0, 0), // stbu
		OPVCC(44, 0, 0, 0), // sth
		OPVCC(45, 0, 0, 0), // sthu
		OPVCC(47, 0, 0, 0), // stmw
		OPVCC(52, 0, 0, 0), // stfs
		OPVCC(53, 0, 0, 0), // stfsu
		OPVCC(54, 0, 0, 0), // stfd
		OPVCC(55, 0, 0, 0): // stfdu
		return D_FORM
	}
	return 0
}

// Encode instructions and create relocation for accessing s+d according to the
// instruction op with source or destination (as appropriate) register reg.
// The caller must call c.cursym.AddRel(c.ctxt, rel) when finished editing rel.
func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32, reuse bool) (o1, o2 uint32, rel obj.Reloc) {
	if c.ctxt.Headtype == objabi.Haix {
		// Every symbol access must be made via a TOC anchor.
		c.ctxt.Diag("symbolAccess called for %s", s.Name)
	}
	var base uint32
	form := c.opform(op)
	if c.ctxt.Flag_shared {
		base = REG_R2
	} else {
		base = REG_R0
	}
	// If reg can be reused when computing the symbol address,
	// use it instead of REGTMP.
	if !reuse {
		o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0)
		o2 = AOP_IRR(op, uint32(reg), REGTMP, 0)
	} else {
		o1 = AOP_IRR(OP_ADDIS, uint32(reg), base, 0)
		o2 = AOP_IRR(op, uint32(reg), uint32(reg), 0)
	}
	var typ objabi.RelocType
	if c.ctxt.Flag_shared {
		switch form {
		case D_FORM:
			typ = objabi.R_ADDRPOWER_TOCREL
		case DS_FORM:
			typ = objabi.R_ADDRPOWER_TOCREL_DS
		}
	} else {
		switch form {
		case D_FORM:
			typ = objabi.R_ADDRPOWER
		case DS_FORM:
			typ = objabi.R_ADDRPOWER_DS
		}
	}
	rel = obj.Reloc{
		Type: typ,
		Off:  int32(c.pc),
		Siz:  8,
		Sym:  s,
		Add:  d,
	}
	return
}

// Determine the mask begin (mb) and mask end (me) values
// for a valid word rotate mask. A valid 32 bit mask is of
// the form 1+0*1+ or 0*1+0*.
//
// Note, me is inclusive.
func decodeMask32(mask uint32) (mb, me uint32, valid bool) {
	mb = uint32(bits.LeadingZeros32(mask))
	me = uint32(32 - bits.TrailingZeros32(mask))
	mbn := uint32(bits.LeadingZeros32(^mask))
	men := uint32(32 - bits.TrailingZeros32(^mask))
	// Check for a wrapping mask (e.g bits at 0 and 31)
	if mb == 0 && me == 32 {
		// swap the inverted values
		mb, me = men, mbn
	}

	// Validate mask is of the binary form 1+0*1+ or 0*1+0*
	// Isolate rightmost 1 (if none 0) and add.
	v := mask
	vp := (v & -v) + v
	// Likewise, check for the wrapping (inverted) case.
	vn := ^v
	vpn := (vn & -vn) + vn
	return mb, (me - 1) & 31, (v&vp == 0 || vn&vpn == 0) && v != 0
}

// Decompose a mask of contiguous bits into a begin (mb) and
// end (me) value.
//
// 64b mask values cannot wrap on any valid PPC64 instruction.
// Only masks of the form 0*1+0* are valid.
//
// Note, me is inclusive.
func decodeMask64(mask int64) (mb, me uint32, valid bool) {
	m := uint64(mask)
	mb = uint32(bits.LeadingZeros64(m))
	me = uint32(64 - bits.TrailingZeros64(m))
	valid = ((m&-m)+m)&m == 0 && m != 0
	return mb, (me - 1) & 63, valid
}

// Load the lower 16 bits of a constant into register r.
func loadl16(r int, d int64) uint32 {
	v := uint16(d)
	if v == 0 {
		// Avoid generating "ori r,r,0", r != 0. Instead, generate the architecturally preferred nop.
		// For example, "ori r31,r31,0" is a special execution serializing nop on Power10 called "exser".
		return NOP
	}
	return LOP_IRR(OP_ORI, uint32(r), uint32(r), uint32(v))
}

// Load the upper 16 bits of a 32b constant into register r.
func loadu32(r int, d int64) uint32 {
	v := int32(d >> 16)
	if isuint32(uint64(d)) {
		return LOP_IRR(OP_ORIS, uint32(r), REGZERO, uint32(v))
	}
	return AOP_IRR(OP_ADDIS, uint32(r), REGZERO, uint32(v))
}

func high16adjusted(d int32) uint16 {
	if d&0x8000 != 0 {
		return uint16((d >> 16) + 1)
	}
	return uint16(d >> 16)
}

func asmout(c *ctxt9, p *obj.Prog, o *Optab, out *[5]uint32) {
	o1 := uint32(0)
	o2 := uint32(0)
	o3 := uint32(0)
	o4 := uint32(0)
	o5 := uint32(0)

	//print("%v => case %d\n", p, o->type);
	switch o.type_ {
	default:
		c.ctxt.Diag("unknown type %d", o.type_)
		prasm(p)

	case 0: /* pseudo ops */
		break

	case 2: /* int/cr/fp op Rb,[Ra],Rd */
		r := int(p.Reg)

		if r == 0 {
			r = int(p.To.Reg)
		}
		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))

	case 3: /* mov $soreg/16con, r ==> addi/ori $i,reg',r */
		d := c.vregoff(&p.From)

		v := int32(d)
		r := int(p.From.Reg)

		if r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0 && (r != 0 || v != 0) {
			c.ctxt.Diag("literal operation on R0\n%v", p)
		}
		if int64(int16(d)) == d {
			// MOVD $int16, Ry  or  MOVD $offset(Rx), Ry
			o1 = AOP_IRR(uint32(OP_ADDI), uint32(p.To.Reg), uint32(r), uint32(v))
		} else {
			// MOVD $uint16, Ry
			if int64(uint16(d)) != d || (r != 0 && r != REGZERO) {
				c.ctxt.Diag("Rule expects a uint16 constant load. got:\n%v", p)
			}
			o1 = LOP_IRR(uint32(OP_ORI), uint32(p.To.Reg), uint32(0), uint32(v))
		}

	case 4: /* add/mul $scon,[r1],r2 */
		v := c.regoff(&p.From)

		r := int(p.Reg)
		if r == 0 {
			r = int(p.To.Reg)
		}
		if r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0 {
			c.ctxt.Diag("literal operation on R0\n%v", p)
		}
		if int32(int16(v)) != v {
			log.Fatalf("mishandled instruction %v", p)
		}
		o1 = AOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))

	case 5: /* syscall */
		o1 = c.oprrr(p.As)

	case 6: /* logical op Rb,[Rs,]Ra; no literal */
		r := int(p.Reg)

		if r == 0 {
			r = int(p.To.Reg)
		}
		// AROTL and AROTLW are extended mnemonics, which map to RLDCL and RLWNM.
		switch p.As {
		case AROTL:
			o1 = AOP_MD(OP_RLDCL, uint32(p.To.Reg), uint32(r), uint32(p.From.Reg), uint32(0))
		case AROTLW:
			o1 = OP_RLW(OP_RLWNM, uint32(p.To.Reg), uint32(r), uint32(p.From.Reg), 0, 31)
		default:
			if p.As == AOR && p.From.Type == obj.TYPE_CONST && p.From.Offset == 0 {
				// Compile "OR $0, Rx, Ry" into ori. If Rx == Ry == 0, this is the preferred
				// hardware no-op. This happens because $0 matches C_REG before C_ZCON.
				o1 = LOP_IRR(OP_ORI, uint32(p.To.Reg), uint32(r), 0)
			} else {
				o1 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
			}
		}

	case 7: /* mov r, soreg ==> stw o(r) */
		r := int(p.To.Reg)
		v := c.regoff(&p.To)
		if int32(int16(v)) != v {
			log.Fatalf("mishandled instruction %v", p)
		}
		// Offsets in DS form stores must be a multiple of 4
		inst := c.opstore(p.As)
		if c.opform(inst) == DS_FORM && v&0x3 != 0 {
			log.Fatalf("invalid offset for DS form load/store %v", p)
		}
		o1 = AOP_IRR(inst, uint32(p.From.Reg), uint32(r), uint32(v))

	case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r), lbz o(r) + extsb r,r */
		r := int(p.From.Reg)
		v := c.regoff(&p.From)
		if int32(int16(v)) != v {
			log.Fatalf("mishandled instruction %v", p)
		}
		// Offsets in DS form loads must be a multiple of 4
		inst := c.opload(p.As)
		if c.opform(inst) == DS_FORM && v&0x3 != 0 {
			log.Fatalf("invalid offset for DS form load/store %v", p)
		}
		o1 = AOP_IRR(inst, uint32(p.To.Reg), uint32(r), uint32(v))

		// Sign extend MOVB operations. This is ignored for other cases (o.size == 4).
		o2 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)

	case 9: /* RLDC Ra, $sh, $mb, Rb */
		sh := uint32(p.RestArgs[0].Addr.Offset) & 0x3F
		mb := uint32(p.RestArgs[1].Addr.Offset) & 0x3F
		o1 = AOP_RRR(c.opirr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), (sh & 0x1F))
		o1 |= (sh & 0x20) >> 4 // sh[5] is placed in bit 1.
		o1 |= (mb & 0x1F) << 6 // mb[0:4] is placed in bits 6-10.
		o1 |= (mb & 0x20)      // mb[5] is placed in bit 5

	case 10: /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */
		r := int(p.Reg)

		if r == 0 {
			r = int(p.To.Reg)
		}
		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(r))

	case 11: /* br/bl bra */
		v := int32(0)

		if p.To.Target() != nil {
			v = int32(p.To.Target().Pc - p.Pc)
			if v&03 != 0 {
				c.ctxt.Diag("odd branch target address\n%v", p)
				v &^= 03
			}

			if v < -(1<<25) || v >= 1<<24 {
				c.ctxt.Diag("branch too far\n%v", p)
			}
		}

		o1 = OP_BR(c.opirr(p.As), uint32(v), 0)
		if p.To.Sym != nil {
			v += int32(p.To.Offset)
			if v&03 != 0 {
				c.ctxt.Diag("odd branch target address\n%v", p)
				v &^= 03
			}
			c.cursym.AddRel(c.ctxt, obj.Reloc{
				Type: objabi.R_CALLPOWER,
				Off:  int32(c.pc),
				Siz:  4,
				Sym:  p.To.Sym,
				Add:  int64(v),
			})
		}
		o2 = NOP // nop, sometimes overwritten by ld r2, 24(r1) when dynamic linking

	case 13: /* mov[bhwd]{z,} r,r */
		// This needs to handle "MOV* $0, Rx".  This shows up because $0 also
		// matches C_REG if r0iszero. This happens because C_REG sorts before C_U16CON
		// TODO: fix the above behavior and cleanup this exception.
		if p.From.Type == obj.TYPE_CONST {
			o1 = LOP_IRR(OP_ADDI, REGZERO, uint32(p.To.Reg), 0)
			break
		}
		if p.To.Type == obj.TYPE_CONST {
			c.ctxt.Diag("cannot move into constant 0\n%v", p)
		}

		switch p.As {
		case AMOVB:
			o1 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.From.Reg), 0)
		case AMOVBZ:
			o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.From.Reg), 0, 24, 31)
		case AMOVH:
			o1 = LOP_RRR(OP_EXTSH, uint32(p.To.Reg), uint32(p.From.Reg), 0)
		case AMOVHZ:
			o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.From.Reg), 0, 16, 31)
		case AMOVW:
			o1 = LOP_RRR(OP_EXTSW, uint32(p.To.Reg), uint32(p.From.Reg), 0)
		case AMOVWZ:
			o1 = OP_RLW(OP_RLDIC, uint32(p.To.Reg), uint32(p.From.Reg), 0, 0, 0) | 1<<5 /* MB=32 */
		case AMOVD:
			o1 = LOP_RRR(OP_OR, uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.From.Reg))
		default:
			c.ctxt.Diag("internal: bad register move/truncation\n%v", p)
		}

	case 14: /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */
		r := uint32(p.Reg)

		if r == 0 {
			r = uint32(p.To.Reg)
		}
		d := c.vregoff(p.GetFrom3())
		switch p.As {

		// These opcodes expect a mask operand that has to be converted into the
		// appropriate operand.  The way these were defined, not all valid masks are possible.
		// Left here for compatibility in case they were used or generated.
		case ARLDCL, ARLDCLCC:
			mb, me, valid := decodeMask64(d)
			if me != 63 || !valid {
				c.ctxt.Diag("invalid mask for rotate: %x (end != bit 63)\n%v", uint64(d), p)
			}
			o1 = AOP_MDS(c.oprrr(p.As), uint32(p.To.Reg), r, uint32(p.From.Reg), mb)

		case ARLDCR, ARLDCRCC:
			mb, me, valid := decodeMask64(d)
			if mb != 0 || !valid {
				c.ctxt.Diag("invalid mask for rotate: %x (start != 0)\n%v", uint64(d), p)
			}
			o1 = AOP_MDS(c.oprrr(p.As), uint32(p.To.Reg), r, uint32(p.From.Reg), me)

		// These opcodes use a shift count like the ppc64 asm, no mask conversion done
		case ARLDICR, ARLDICRCC:
			me := uint32(d)
			sh := c.regoff(&p.From)
			if me < 0 || me > 63 || sh > 63 {
				c.ctxt.Diag("Invalid me or sh for RLDICR: %x %x\n%v", int(d), sh, p)
			}
			o1 = AOP_MD(c.oprrr(p.As), uint32(p.To.Reg), r, uint32(sh), me)

		case ARLDICL, ARLDICLCC, ARLDIC, ARLDICCC:
			mb := uint32(d)
			sh := c.regoff(&p.From)
			if mb < 0 || mb > 63 || sh > 63 {
				c.ctxt.Diag("Invalid mb or sh for RLDIC, RLDICL: %x %x\n%v", mb, sh, p)
			}
			o1 = AOP_MD(c.oprrr(p.As), uint32(p.To.Reg), r, uint32(sh), mb)

		case ACLRLSLDI:
			// This is an extended mnemonic defined in the ISA section C.8.1
			// clrlsldi ra,rs,b,n --> rldic ra,rs,n,b-n
			// It maps onto RLDIC so is directly generated here based on the operands from
			// the clrlsldi.
			n := int32(d)
			b := c.regoff(&p.From)
			if n > b || b > 63 {
				c.ctxt.Diag("Invalid n or b for CLRLSLDI: %x %x\n%v", n, b, p)
			}
			o1 = AOP_MD(OP_RLDIC, uint32(p.To.Reg), r, uint32(n), uint32(b)-uint32(n))

		default:
			c.ctxt.Diag("unexpected op in rldc case\n%v", p)
		}

	case 16: /* bc bo,bi,bra */
		a := 0

		r := int(p.Reg)

		if p.From.Type == obj.TYPE_CONST {
			a = int(c.regoff(&p.From))
		} else if p.From.Type == obj.TYPE_REG {
			if r != 0 {
				c.ctxt.Diag("unexpected register setting for branch with CR: %d\n", r)
			}
			// BI values for the CR
			switch p.From.Reg {
			case REG_CR0:
				r = BI_CR0
			case REG_CR1:
				r = BI_CR1
			case REG_CR2:
				r = BI_CR2
			case REG_CR3:
				r = BI_CR3
			case REG_CR4:
				r = BI_CR4
			case REG_CR5:
				r = BI_CR5
			case REG_CR6:
				r = BI_CR6
			case REG_CR7:
				r = BI_CR7
			default:
				c.ctxt.Diag("unrecognized register: expecting CR\n")
			}
		}
		v := int32(0)
		if p.To.Target() != nil {
			v = int32(p.To.Target().Pc - p.Pc)
		}
		if v&03 != 0 {
			c.ctxt.Diag("odd branch target address\n%v", p)
			v &^= 03
		}

		if v < -(1<<16) || v >= 1<<15 {
			c.ctxt.Diag("branch too far\n%v", p)
		}
		o1 = OP_BC(c.opirr(p.As), uint32(a), uint32(r), uint32(v), 0)

	case 17:
		var bo int32
		bi := int(p.Reg)

		if p.From.Reg == REG_CR {
			c.ctxt.Diag("unrecognized register: expected CR0-CR7\n")
		}
		bi = int(p.From.Reg&0x7) * 4

		bo = BO_BCR

		switch p.As {
		case ABLT:
			bi += BI_LT
		case ABGT:
			bi += BI_GT
		case ABEQ:
			bi += BI_EQ
		case ABNE:
			bo = BO_NOTBCR
			bi += BI_EQ
		case ABLE:
			bo = BO_NOTBCR
			bi += BI_GT
		case ABGE:
			bo = BO_NOTBCR
			bi += BI_LT
		case ABVS:
			bi += BI_FU
		case ABVC:
			bo = BO_NOTBCR
			bi += BI_FU
		default:
			c.ctxt.Diag("unexpected instruction: expecting BGT, BEQ, BNE, BLE, BGE, BVS, BVC \n%v", p)

		}
		if oclass(&p.To) == C_LR {
			o1 = OPVCC(19, 16, 0, 0)
		} else {
			c.ctxt.Diag("bad optab entry (17): %d\n%v", p.To.Class, p)
		}

		o1 = OP_BCR(o1, uint32(bo), uint32(bi))

	case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */
		var v int32
		var bh uint32 = 0
		if p.As == ABC || p.As == ABCL {
			v = c.regoff(&p.From) & 31
		} else {
			v = 20 /* unconditional */
		}
		r := int(p.Reg)
		if r == 0 {
			r = 0
		}
		switch oclass(&p.To) {
		case C_CTR:
			o1 = OPVCC(19, 528, 0, 0)

		case C_LR:
			o1 = OPVCC(19, 16, 0, 0)

		default:
			c.ctxt.Diag("bad optab entry (18): %d\n%v", p.To.Class, p)
			v = 0
		}

		// Insert optional branch hint for bclr[l]/bcctr[l]
		if p.From3Type() != obj.TYPE_NONE {
			bh = uint32(p.GetFrom3().Offset)
			if bh == 2 || bh > 3 {
				log.Fatalf("BH must be 0,1,3 for %v", p)
			}
			o1 |= bh << 11
		}

		if p.As == ABL || p.As == ABCL {
			o1 |= 1
		}
		o1 = OP_BCR(o1, uint32(v), uint32(r))

	case 19: /* mov $lcon,r ==> cau+or */
		d := c.vregoff(&p.From)
		if o.ispfx {
			o1, o2 = pfxadd(p.To.Reg, REG_R0, PFX_R_ABS, d)
		} else {
			o1 = loadu32(int(p.To.Reg), d)
			o2 = LOP_IRR(OP_ORI, uint32(p.To.Reg), uint32(p.To.Reg), uint32(int32(d)))
		}

	case 20: /* add $ucon,,r | addis $addcon,r,r */
		v := c.regoff(&p.From)

		r := int(p.Reg)
		if r == 0 {
			r = int(p.To.Reg)
		}
		o1 = AOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))

	case 21: /* or $u32con,rx[,ry] => oris + ori (similar for xor) */
		var opu, opl uint32
		r := uint32(p.Reg)
		if r == 0 {
			r = uint32(p.To.Reg)
		}
		switch p.As {
		case AOR:
			opu, opl = OP_ORIS, OP_ORI
		case AXOR:
			opu, opl = OP_XORIS, OP_XORI
		default:
			c.ctxt.Diag("unhandled opcode.\n%v", p)
		}
		o1 = LOP_IRR(opu, uint32(p.To.Reg), r, uint32(p.From.Offset>>16))
		o2 = LOP_IRR(opl, uint32(p.To.Reg), uint32(p.To.Reg), uint32(p.From.Offset)&0xFFFF)

	case 22: /* add $lcon/$andcon,r1,r2 ==> oris+ori+add/ori+add, add $s34con,r1 ==> addis+ori+slw+ori+add */
		if p.To.Reg == REGTMP || p.Reg == REGTMP {
			c.ctxt.Diag("can't synthesize large constant\n%v", p)
		}
		d := c.vregoff(&p.From)
		r := int(p.Reg)
		if r == 0 {
			r = int(p.To.Reg)
		}
		if p.From.Sym != nil {
			c.ctxt.Diag("%v is not supported", p)
		}
		if o.ispfx {
			o1, o2 = pfxadd(p.To.Reg, int16(r), PFX_R_ABS, d)
		} else if o.size == 8 {
			o1 = LOP_IRR(OP_ORI, REGTMP, REGZERO, uint32(int32(d)))          // tmp = uint16(d)
			o2 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r)) // to = tmp + from
		} else if o.size == 12 {
			// Note, o1 is ADDIS if d is negative, ORIS otherwise.
			o1 = loadu32(REGTMP, d)                                          // tmp = d & 0xFFFF0000
			o2 = loadl16(REGTMP, d)                                          // tmp |= d & 0xFFFF
			o3 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r)) // to = from + tmp
		} else {
			// For backwards compatibility with GOPPC64 < 10, generate 34b constants in register.
			o1 = LOP_IRR(OP_ADDIS, REGZERO, REGTMP, uint32(d>>32)) // tmp = sign_extend((d>>32)&0xFFFF0000)
			o2 = loadl16(REGTMP, d>>16)                            // tmp |= (d>>16)&0xFFFF
			o3 = AOP_MD(OP_RLDICR, REGTMP, REGTMP, 16, 63-16)      // tmp <<= 16
			o4 = loadl16(REGTMP, int64(uint16(d)))                 // tmp |= d&0xFFFF
			o5 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
		}

	case 23: /* and $lcon/$addcon,r1,r2 ==> oris+ori+and/addi+and */
		if p.To.Reg == REGTMP || p.Reg == REGTMP {
			c.ctxt.Diag("can't synthesize large constant\n%v", p)
		}
		d := c.vregoff(&p.From)
		r := int(p.Reg)
		if r == 0 {
			r = int(p.To.Reg)
		}

		// With S16CON operand, generate 2 instructions using ADDI for signed value,
		// with 32CON operand generate 3 instructions.
		if o.size == 8 {
			o1 = LOP_IRR(OP_ADDI, REGZERO, REGTMP, uint32(int32(d)))
			o2 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
		} else {
			o1 = loadu32(REGTMP, d)
			o2 = loadl16(REGTMP, d)
			o3 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), REGTMP, uint32(r))
		}
		if p.From.Sym != nil {
			c.ctxt.Diag("%v is not supported", p)
		}

	case 24: /* lfd fA,float64(0) -> xxlxor xsA,xsaA,xsaA + fneg for -0 */
		o1 = AOP_XX3I(c.oprrr(AXXLXOR), uint32(p.To.Reg), uint32(p.To.Reg), uint32(p.To.Reg), uint32(0))
		// This is needed for -0.
		if o.size == 8 {
			o2 = AOP_RRR(c.oprrr(AFNEG), uint32(p.To.Reg), 0, uint32(p.To.Reg))
		}

	case 25:
		/* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */
		v := c.regoff(&p.From)

		if v < 0 {
			v = 0
		} else if v > 63 {
			v = 63
		}
		r := int(p.Reg)
		if r == 0 {
			r = int(p.To.Reg)
		}
		var a int
		op := uint32(0)
		switch p.As {
		case ASLD, ASLDCC:
			a = int(63 - v)
			op = OP_RLDICR

		case ASRD, ASRDCC:
			a = int(v)
			v = 64 - v
			op = OP_RLDICL
		case AROTL:
			a = int(0)
			op = OP_RLDICL
		case AEXTSWSLI, AEXTSWSLICC:
			a = int(v)
		default:
			c.ctxt.Diag("unexpected op in sldi case\n%v", p)
			a = 0
			o1 = 0
		}

		if p.As == AEXTSWSLI || p.As == AEXTSWSLICC {
			o1 = AOP_EXTSWSLI(OP_EXTSWSLI, uint32(r), uint32(p.To.Reg), uint32(v))

		} else {
			o1 = AOP_MD(op, uint32(p.To.Reg), uint32(r), uint32(v), uint32(a))
		}
		if p.As == ASLDCC || p.As == ASRDCC || p.As == AEXTSWSLICC {
			o1 |= 1 // Set the condition code bit
		}

	case 26: /* mov $lsext/auto/oreg,,r2 ==> addis+addi */
		v := c.vregoff(&p.From)
		r := int(p.From.Reg)
		var rel *obj.Reloc

		switch p.From.Name {
		case obj.NAME_EXTERN, obj.NAME_STATIC:
			// Load a 32 bit constant, or relocation depending on if a symbol is attached
			var rel1 obj.Reloc
			o1, o2, rel1 = c.symbolAccess(p.From.Sym, v, p.To.Reg, OP_ADDI, true)
			rel = &rel1
		default:
			// Add a 32 bit offset to a register.
			o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(int32(v))))
			o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
		}

		if o.ispfx {
			if rel == nil {
				o1, o2 = pfxadd(p.To.Reg, int16(r), PFX_R_ABS, v)
			} else {
				o1, o2 = pfxadd(p.To.Reg, REG_R0, PFX_R_PCREL, 0)
				rel.Type = objabi.R_ADDRPOWER_PCREL34
			}
		}
		if rel != nil {
			c.cursym.AddRel(c.ctxt, *rel)
		}

	case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
		v := c.regoff(p.GetFrom3())

		r := int(p.From.Reg)
		o1 = AOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))

	case 28: /* subc r1,$lcon,r2 ==> cau+or+subfc */
		if p.To.Reg == REGTMP || p.From.Reg == REGTMP {
			c.ctxt.Diag("can't synthesize large constant\n%v", p)
		}
		v := c.vregoff(p.GetFrom3())
		o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(v)>>16)
		o2 = loadl16(REGTMP, v)
		o3 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), REGTMP)
		if p.From.Sym != nil {
			c.ctxt.Diag("%v is not supported", p)
		}

	case 29: /* rldic[lr]? $sh,s,$mask,a -- left, right, plain give different masks */
		sh := uint32(c.regoff(&p.From))
		d := c.vregoff(p.GetFrom3())
		mb, me, valid := decodeMask64(d)
		var a uint32
		switch p.As {
		case ARLDC, ARLDCCC:
			a = mb
			if me != (63-sh) || !valid {
				c.ctxt.Diag("invalid mask for shift: %016x (mb=%d,me=%d) (shift %d)\n%v", uint64(d), mb, me, sh, p)
			}

		case ARLDCL, ARLDCLCC:
			a = mb
			if mb != 63 || !valid {
				c.ctxt.Diag("invalid mask for shift: %016x (mb=%d,me=%d) (shift %d)\n%v", uint64(d), mb, me, sh, p)
			}

		case ARLDCR, ARLDCRCC:
			a = me
			if mb != 0 || !valid {
				c.ctxt.Diag("invalid mask for shift: %016x (mb=%d,me=%d) (shift %d)\n%v", uint64(d), mb, me, sh, p)
			}

		default:
			c.ctxt.Diag("unexpected op in rldic case\n%v", p)
		}
		o1 = AOP_MD(c.opirr(p.As), uint32(p.To.Reg), uint32(p.Reg), sh, a)

	case 30: /* rldimi $sh,s,$mask,a */
		sh := uint32(c.regoff(&p.From))
		d := c.vregoff(p.GetFrom3())

		// Original opcodes had mask operands which had to be converted to a shift count as expected by
		// the ppc64 asm.
		switch p.As {
		case ARLDMI, ARLDMICC:
			mb, me, valid := decodeMask64(d)
			if me != (63-sh) || !valid {
				c.ctxt.Diag("invalid mask for shift: %x %x (shift %d)\n%v", uint64(d), me, sh, p)
			}
			o1 = AOP_MD(c.opirr(p.As), uint32(p.To.Reg), uint32(p.Reg), sh, mb)

		// Opcodes with shift count operands.
		case ARLDIMI, ARLDIMICC:
			o1 = AOP_MD(c.opirr(p.As), uint32(p.To.Reg), uint32(p.Reg), sh, uint32(d))
		}

	case 31: /* dword */
		d := c.vregoff(&p.From)

		if c.ctxt.Arch.ByteOrder == binary.BigEndian {
			o1 = uint32(d >> 32)
			o2 = uint32(d)
		} else {
			o1 = uint32(d)
			o2 = uint32(d >> 32)
		}

		if p.From.Sym != nil {
			c.cursym.AddRel(c.ctxt, obj.Reloc{
				Type: objabi.R_ADDR,
				Off:  int32(c.pc),
				Siz:  8,
				Sym:  p.From.Sym,
				Add:  p.From.Offset,
			})
			o2 = 0
			o1 = o2
		}

	case 32: /* fmul frc,fra,frd */
		r := int(p.Reg)

		if r == 0 {
			r = int(p.To.Reg)
		}
		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), 0) | (uint32(p.From.Reg)&31)<<6

	case 33: /* fabs [frb,]frd; fmr. frb,frd */
		r := int(p.From.Reg)

		if oclass(&p.From) == C_NONE {
			r = int(p.To.Reg)
		}
		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), 0, uint32(r))

	case 34: /* FMADDx fra,frb,frc,frt (t=a*c±b) */
		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg)) | (uint32(p.GetFrom3().Reg)&31)<<6

	case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */
		v := c.regoff(&p.To)
		r := int(p.To.Reg)
		// Offsets in DS form stores must be a multiple of 4
		if o.ispfx {
			o1, o2 = pfxstore(p.As, p.From.Reg, int16(r), PFX_R_ABS)
			o1 |= uint32((v >> 16) & 0x3FFFF)
			o2 |= uint32(v & 0xFFFF)
		} else {
			inst := c.opstore(p.As)
			if c.opform(inst) == DS_FORM && v&0x3 != 0 {
				log.Fatalf("invalid offset for DS form load/store %v", p)
			}
			o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
			o2 = AOP_IRR(inst, uint32(p.From.Reg), REGTMP, uint32(v))
		}

	case 36: /* mov b/bz/h/hz lext/lauto/lreg,r ==> lbz+extsb/lbz/lha/lhz etc */
		v := c.regoff(&p.From)
		r := int(p.From.Reg)

		if o.ispfx {
			o1, o2 = pfxload(p.As, p.To.Reg, int16(r), PFX_R_ABS)
			o1 |= uint32((v >> 16) & 0x3FFFF)
			o2 |= uint32(v & 0xFFFF)
		} else {
			if o.a6 == C_REG {
				// Reuse the base register when loading a GPR (C_REG) to avoid
				// using REGTMP (R31) when possible.
				o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), uint32(r), uint32(high16adjusted(v)))
				o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(p.To.Reg), uint32(v))
			} else {
				o1 = AOP_IRR(OP_ADDIS, uint32(REGTMP), uint32(r), uint32(high16adjusted(v)))
				o2 = AOP_IRR(c.opload(p.As), uint32(p.To.Reg), uint32(REGTMP), uint32(v))
			}
		}

		// Sign extend MOVB if needed
		o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)

	case 40: /* word */
		o1 = uint32(c.regoff(&p.From))

	case 41: /* stswi */
		if p.To.Type == obj.TYPE_MEM && p.To.Index == 0 && p.To.Offset != 0 {
			c.ctxt.Diag("Invalid addressing mode used in index type instruction: %v", p.As)
		}

		o1 = AOP_RRR(c.opirr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), 0) | (uint32(c.regoff(p.GetFrom3()))&0x7F)<<11

	case 42: /* lswi */
		if p.From.Type == obj.TYPE_MEM && p.From.Index == 0 && p.From.Offset != 0 {
			c.ctxt.Diag("Invalid addressing mode used in index type instruction: %v", p.As)
		}
		o1 = AOP_RRR(c.opirr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), 0) | (uint32(c.regoff(p.GetFrom3()))&0x7F)<<11

	case 43: /* data cache instructions: op (Ra+[Rb]), [th|l] */
		/* TH field for dcbt/dcbtst: */
		/* 0 = Block access - program will soon access EA. */
		/* 8-15 = Stream access - sequence of access (data stream). See section 4.3.2 of the ISA for details. */
		/* 16 = Block access - program will soon make a transient access to EA. */
		/* 17 = Block access - program will not access EA for a long time. */

		/* L field for dcbf: */
		/* 0 = invalidates the block containing EA in all processors. */
		/* 1 = same as 0, but with limited scope (i.e. block in the current processor will not be reused soon). */
		/* 3 = same as 1, but with even more limited scope (i.e. block in the current processor primary cache will not be reused soon). */
		if p.To.Type == obj.TYPE_NONE {
			o1 = AOP_RRR(c.oprrr(p.As), 0, uint32(p.From.Index), uint32(p.From.Reg))
		} else {
			th := c.regoff(&p.To)
			o1 = AOP_RRR(c.oprrr(p.As), uint32(th), uint32(p.From.Index), uint32(p.From.Reg))
		}

	case 44: /* indexed store */
		o1 = AOP_RRR(c.opstorex(p.As), uint32(p.From.Reg), uint32(p.To.Index), uint32(p.To.Reg))

	case 45: /* indexed load */
		switch p.As {
		/* The assembler accepts a 4-operand l*arx instruction. The fourth operand is an Exclusive Access Hint (EH) */
		/* The EH field can be used as a lock acquire/release hint as follows: */
		/* 0 = Atomic Update (fetch-and-operate or similar algorithm) */
		/* 1 = Exclusive Access (lock acquire and release) */
		case ALBAR, ALHAR, ALWAR, ALDAR:
			if p.From3Type() != obj.TYPE_NONE {
				eh := int(c.regoff(p.GetFrom3()))
				if eh > 1 {
					c.ctxt.Diag("illegal EH field\n%v", p)
				}
				o1 = AOP_RRRI(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg), uint32(eh))
			} else {
				o1 = AOP_RRR(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
			}
		default:
			o1 = AOP_RRR(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
		}
	case 46: /* plain op */
		o1 = c.oprrr(p.As)

	case 47: /* op Ra, Rd; also op [Ra,] Rd */
		r := int(p.From.Reg)

		if r == 0 {
			r = int(p.To.Reg)
		}
		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), 0)

	case 48: /* op Rs, Ra */
		r := int(p.From.Reg)

		if r == 0 {
			r = int(p.To.Reg)
		}
		o1 = LOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), 0)

	case 49: /* op Rb; op $n, Rb */
		if p.From.Type != obj.TYPE_REG { /* tlbie $L, rB */
			v := c.regoff(&p.From) & 1
			o1 = AOP_RRR(c.oprrr(p.As), 0, 0, uint32(p.To.Reg)) | uint32(v)<<21
		} else {
			o1 = AOP_RRR(c.oprrr(p.As), 0, 0, uint32(p.From.Reg))
		}

	case 50: /* rem[u] r1[,r2],r3 */
		r := int(p.Reg)

		if r == 0 {
			r = int(p.To.Reg)
		}
		v := c.oprrr(p.As)
		t := v & (1<<10 | 1) /* OE|Rc */
		o1 = AOP_RRR(v&^t, REGTMP, uint32(r), uint32(p.From.Reg))
		o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, uint32(p.From.Reg))
		o3 = AOP_RRR(OP_SUBF|t, uint32(p.To.Reg), REGTMP, uint32(r))
		if p.As == AREMU {
			o4 = o3

			/* Clear top 32 bits */
			o3 = OP_RLW(OP_RLDIC, REGTMP, REGTMP, 0, 0, 0) | 1<<5
		}

	case 51: /* remd[u] r1[,r2],r3 */
		r := int(p.Reg)

		if r == 0 {
			r = int(p.To.Reg)
		}
		v := c.oprrr(p.As)
		t := v & (1<<10 | 1) /* OE|Rc */
		o1 = AOP_RRR(v&^t, REGTMP, uint32(r), uint32(p.From.Reg))
		o2 = AOP_RRR(OP_MULLD, REGTMP, REGTMP, uint32(p.From.Reg))
		o3 = AOP_RRR(OP_SUBF|t, uint32(p.To.Reg), REGTMP, uint32(r))
		/* cases 50,51: removed; can be reused. */

		/* cases 50,51: removed; can be reused. */

	case 52: /* mtfsbNx cr(n) */
		v := c.regoff(&p.From) & 31

		o1 = AOP_RRR(c.oprrr(p.As), uint32(v), 0, 0)

	case 53: /* mffsX ,fr1 */
		o1 = AOP_RRR(OP_MFFS, uint32(p.To.Reg), 0, 0)

	case 55: /* op Rb, Rd */
		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), 0, uint32(p.From.Reg))

	case 56: /* sra $sh,[s,]a; srd $sh,[s,]a */
		v := c.regoff(&p.From)

		r := int(p.Reg)
		if r == 0 {
			r = int(p.To.Reg)
		}
		o1 = AOP_RRR(c.opirr(p.As), uint32(r), uint32(p.To.Reg), uint32(v)&31)
		if (p.As == ASRAD || p.As == ASRADCC) && (v&0x20 != 0) {
			o1 |= 1 << 1 /* mb[5] */
		}

	case 57: /* slw $sh,[s,]a -> rlwinm ... */
		v := c.regoff(&p.From)

		r := int(p.Reg)
		if r == 0 {
			r = int(p.To.Reg)
		}

		/*
			 * Let user (gs) shoot himself in the foot.
			 * qc has already complained.
			 *
			if(v < 0 || v > 31)
				ctxt->diag("illegal shift %ld\n%v", v, p);
		*/
		if v < 0 {
			v = 0
		} else if v > 32 {
			v = 32
		}
		var mask [2]uint8
		switch p.As {
		case AROTLW:
			mask[0], mask[1] = 0, 31
		case ASRW, ASRWCC:
			mask[0], mask[1] = uint8(v), 31
			v = 32 - v
		default:
			mask[0], mask[1] = 0, uint8(31-v)
		}
		o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(r), uint32(v), uint32(mask[0]), uint32(mask[1]))
		if p.As == ASLWCC || p.As == ASRWCC {
			o1 |= 1 // set the condition code
		}

	case 58: /* logical $andcon,[s],a */
		v := c.regoff(&p.From)

		r := int(p.Reg)
		if r == 0 {
			r = int(p.To.Reg)
		}
		o1 = LOP_IRR(c.opirr(p.As), uint32(p.To.Reg), uint32(r), uint32(v))

	case 60: /* tw to,a,b */
		r := int(c.regoff(&p.From) & 31)

		o1 = AOP_RRR(c.oprrr(p.As), uint32(r), uint32(p.Reg), uint32(p.To.Reg))

	case 61: /* tw to,a,$simm */
		r := int(c.regoff(&p.From) & 31)

		v := c.regoff(&p.To)
		o1 = AOP_IRR(c.opirr(p.As), uint32(r), uint32(p.Reg), uint32(v))

	case 62: /* clrlslwi $sh,s,$mask,a */
		v := c.regoff(&p.From)
		n := c.regoff(p.GetFrom3())
		// This is an extended mnemonic described in the ISA C.8.2
		// clrlslwi ra,rs,b,n -> rlwinm ra,rs,n,b-n,31-n
		// It maps onto rlwinm which is directly generated here.
		if n > v || v >= 32 {
			c.ctxt.Diag("Invalid n or b for CLRLSLWI: %x %x\n%v", v, n, p)
		}

		o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.Reg), uint32(n), uint32(v-n), uint32(31-n))

	case 63: /* rlwimi/rlwnm/rlwinm [$sh,b],s,[$mask or mb,me],a*/
		var mb, me uint32
		if len(p.RestArgs) == 1 { // Mask needs decomposed into mb and me.
			var valid bool
			// Note, optab rules ensure $mask is a 32b constant.
			mb, me, valid = decodeMask32(uint32(p.RestArgs[0].Addr.Offset))
			if !valid {
				c.ctxt.Diag("cannot generate mask #%x\n%v", uint64(p.RestArgs[0].Addr.Offset), p)
			}
		} else { // Otherwise, mask is already passed as mb and me in RestArgs.
			mb, me = uint32(p.RestArgs[0].Addr.Offset), uint32(p.RestArgs[1].Addr.Offset)
		}
		if p.From.Type == obj.TYPE_CONST {
			o1 = OP_RLW(c.opirr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(p.From.Offset), mb, me)
		} else {
			o1 = OP_RLW(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(p.From.Reg), mb, me)
		}

	case 64: /* mtfsf fr[, $m] {,fpcsr} */
		var v int32
		if p.From3Type() != obj.TYPE_NONE {
			v = c.regoff(p.GetFrom3()) & 255
		} else {
			v = 255
		}
		o1 = OP_MTFSF | uint32(v)<<17 | uint32(p.From.Reg)<<11

	case 65: /* MOVFL $imm,FPSCR(n) => mtfsfi crfd,imm */
		if p.To.Reg == 0 {
			c.ctxt.Diag("must specify FPSCR(n)\n%v", p)
		}
		o1 = OP_MTFSFI | (uint32(p.To.Reg)&15)<<23 | (uint32(c.regoff(&p.From))&31)<<12

	case 66: /* mov spr,r1; mov r1,spr */
		var r int
		var v int32
		if REG_R0 <= p.From.Reg && p.From.Reg <= REG_R31 {
			r = int(p.From.Reg)
			v = int32(p.To.Reg)
			o1 = OPVCC(31, 467, 0, 0) /* mtspr */
		} else {
			r = int(p.To.Reg)
			v = int32(p.From.Reg)
			o1 = OPVCC(31, 339, 0, 0) /* mfspr */
		}

		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.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 */
		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, 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) | v<<12

	case 70: /* cmp* r,r,cr or cmp*i r,i,cr or fcmp f,f,cr or cmpeqb r,r */
		r := uint32(p.Reg&7) << 2
		if p.To.Type == obj.TYPE_CONST {
			o1 = AOP_IRR(c.opirr(p.As), r, uint32(p.From.Reg), uint32(uint16(p.To.Offset)))
		} else {
			o1 = AOP_RRR(c.oprrr(p.As), r, uint32(p.From.Reg), uint32(p.To.Reg))
		}

	case 72: /* slbmte (Rb+Rs -> slb[Rb]) -> Rs, Rb */
		o1 = AOP_RRR(c.oprrr(p.As), uint32(p.From.Reg), 0, uint32(p.To.Reg))

	case 73: /* mcrfs crfD,crfS */
		if p.From.Type != obj.TYPE_REG || p.From.Reg != REG_FPSCR || p.To.Type != obj.TYPE_REG || p.To.Reg < REG_CR0 || REG_CR7 < p.To.Reg {
			c.ctxt.Diag("illegal FPSCR/CR field number\n%v", p)
		}
		o1 = AOP_RRR(OP_MCRFS, ((uint32(p.To.Reg) & 7) << 2), ((0 & 7) << 2), 0)

	case 77: /* syscall $scon, syscall Rx */
		if p.From.Type == obj.TYPE_CONST {
			if p.From.Offset > BIG || p.From.Offset < -BIG {
				c.ctxt.Diag("illegal syscall, sysnum too large: %v", p)
			}
			o1 = AOP_IRR(OP_ADDI, REGZERO, REGZERO, uint32(p.From.Offset))
		} else if p.From.Type == obj.TYPE_REG {
			o1 = LOP_RRR(OP_OR, REGZERO, uint32(p.From.Reg), uint32(p.From.Reg))
		} else {
			c.ctxt.Diag("illegal syscall: %v", p)
			o1 = 0x7fe00008 // trap always
		}

		o2 = c.oprrr(p.As)
		o3 = AOP_RRR(c.oprrr(AXOR), REGZERO, REGZERO, REGZERO) // XOR R0, R0

	case 78: /* undef */
		o1 = 0 /* "An instruction consisting entirely of binary 0s is guaranteed
		   always to be an illegal instruction."  */

	/* relocation operations */
	case 74:
		v := c.vregoff(&p.To)
		// Offsets in DS form stores must be a multiple of 4
		inst := c.opstore(p.As)

		// Can't reuse base for store instructions.
		var rel obj.Reloc
		o1, o2, rel = c.symbolAccess(p.To.Sym, v, p.From.Reg, inst, false)

		// Rewrite as a prefixed store if supported.
		if o.ispfx {
			o1, o2 = pfxstore(p.As, p.From.Reg, REG_R0, PFX_R_PCREL)
			rel.Type = objabi.R_ADDRPOWER_PCREL34
		} else if c.opform(inst) == DS_FORM && v&0x3 != 0 {
			log.Fatalf("invalid offset for DS form load/store %v", p)
		}
		c.cursym.AddRel(c.ctxt, rel)

	case 75: // 32 bit offset symbol loads (got/toc/addr)
		v := p.From.Offset

		// Offsets in DS form loads must be a multiple of 4
		inst := c.opload(p.As)
		var rel obj.Reloc
		switch p.From.Name {
		case obj.NAME_GOTREF, obj.NAME_TOCREF:
			if v != 0 {
				c.ctxt.Diag("invalid offset for GOT/TOC access %v", p)
			}
			o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0)
			o2 = AOP_IRR(inst, uint32(p.To.Reg), uint32(p.To.Reg), 0)
			rel.Off = int32(c.pc)
			rel.Siz = 8
			rel.Sym = p.From.Sym
			switch p.From.Name {
			case obj.NAME_GOTREF:
				rel.Type = objabi.R_ADDRPOWER_GOT
			case obj.NAME_TOCREF:
				rel.Type = objabi.R_ADDRPOWER_TOCREL_DS
			}
		default:
			reuseBaseReg := o.a6 == C_REG
			// Reuse To.Reg as base register if it is a GPR.
			o1, o2, rel = c.symbolAccess(p.From.Sym, v, p.To.Reg, inst, reuseBaseReg)
		}

		// Convert to prefixed forms if supported.
		if o.ispfx {
			switch rel.Type {
			case objabi.R_ADDRPOWER, objabi.R_ADDRPOWER_DS,
				objabi.R_ADDRPOWER_TOCREL, objabi.R_ADDRPOWER_TOCREL_DS:
				o1, o2 = pfxload(p.As, p.To.Reg, REG_R0, PFX_R_PCREL)
				rel.Type = objabi.R_ADDRPOWER_PCREL34
			case objabi.R_POWER_TLS_IE:
				o1, o2 = pfxload(p.As, p.To.Reg, REG_R0, PFX_R_PCREL)
				rel.Type = objabi.R_POWER_TLS_IE_PCREL34
			case objabi.R_ADDRPOWER_GOT:
				o1, o2 = pfxload(p.As, p.To.Reg, REG_R0, PFX_R_PCREL)
				rel.Type = objabi.R_ADDRPOWER_GOT_PCREL34
			default:
				// We've failed to convert a TOC-relative relocation to a PC-relative one.
				log.Fatalf("Unable convert TOC-relative relocation %v to PC-relative", rel.Type)
			}
		} else if c.opform(inst) == DS_FORM && v&0x3 != 0 {
			log.Fatalf("invalid offset for DS form load/store %v", p)
		}
		c.cursym.AddRel(c.ctxt, rel)

		o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)

	case 79:
		if p.From.Offset != 0 {
			c.ctxt.Diag("invalid offset against tls var %v", p)
		}
		var typ objabi.RelocType
		if !o.ispfx {
			o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R13, 0)
			o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), uint32(p.To.Reg), 0)
			typ = objabi.R_POWER_TLS_LE
		} else {
			o1, o2 = pfxadd(p.To.Reg, REG_R13, PFX_R_ABS, 0)
			typ = objabi.R_POWER_TLS_LE_TPREL34
		}
		c.cursym.AddRel(c.ctxt, obj.Reloc{
			Type: typ,
			Off:  int32(c.pc),
			Siz:  8,
			Sym:  p.From.Sym,
		})

	case 80:
		if p.From.Offset != 0 {
			c.ctxt.Diag("invalid offset against tls var %v", p)
		}
		typ := objabi.R_POWER_TLS_IE
		if !o.ispfx {
			o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0)
			o2 = AOP_IRR(c.opload(AMOVD), uint32(p.To.Reg), uint32(p.To.Reg), 0)
		} else {
			o1, o2 = pfxload(p.As, p.To.Reg, REG_R0, PFX_R_PCREL)
			typ = objabi.R_POWER_TLS_IE_PCREL34
		}
		c.cursym.AddRel(c.ctxt, obj.Reloc{
			Type: typ,
			Off:  int32(c.pc),
			Siz:  8,
			Sym:  p.From.Sym,
		})
		o3 = AOP_RRR(OP_ADD, uint32(p.To.Reg), uint32(p.To.Reg), REG_R13)
		c.cursym.AddRel(c.ctxt, obj.Reloc{
			Type: objabi.R_POWER_TLS,
			Off:  int32(c.pc) + 8,
			Siz:  4,
			Sym:  p.From.Sym,
		})

	case 82: /* vector instructions, VX-form and VC-form */
		if p.From.Type == obj.TYPE_REG {
			/* reg reg none OR reg reg reg */
			/* 3-register operand order: VRA, VRB, VRT */
			/* 2-register operand order: VRA, VRT */
			o1 = AOP_RRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
		} else if p.From3Type() == obj.TYPE_CONST {
			/* imm imm reg reg */
			/* operand order: SIX, VRA, ST, VRT */
			six := int(c.regoff(&p.From))
			st := int(c.regoff(p.GetFrom3()))
			o1 = AOP_IIRR(c.opiirr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(st), uint32(six))
		} else if p.From3Type() == obj.TYPE_NONE && p.Reg != 0 {
			/* imm reg reg */
			/* operand order: UIM, VRB, VRT */
			uim := int(c.regoff(&p.From))
			o1 = AOP_VIRR(c.opirr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(uim))
		} else {
			/* imm reg */
			/* operand order: SIM, VRT */
			sim := int(c.regoff(&p.From))
			o1 = AOP_IR(c.opirr(p.As), uint32(p.To.Reg), uint32(sim))
		}

	case 83: /* vector instructions, VA-form */
		if p.From.Type == obj.TYPE_REG {
			/* reg reg reg reg */
			/* 4-register operand order: VRA, VRB, VRC, VRT */
			o1 = AOP_RRRR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg))
		} else if p.From.Type == obj.TYPE_CONST {
			/* imm reg reg reg */
			/* operand order: SHB, VRA, VRB, VRT */
			shb := int(c.regoff(&p.From))
			o1 = AOP_IRRR(c.opirrr(p.As), uint32(p.To.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg), uint32(shb))
		}

	case 84: // ISEL BC,RA,RB,RT -> isel rt,ra,rb,bc
		bc := c.vregoff(&p.From)
		if o.a1 == C_CRBIT {
			// CR bit is encoded as a register, not a constant.
			bc = int64(p.From.Reg)
		}

		// rt = To.Reg, ra = p.Reg, rb = p.From3.Reg
		o1 = AOP_ISEL(OP_ISEL, uint32(p.To.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg), uint32(bc))

	case 85: /* vector instructions, VX-form */
		/* reg none reg */
		/* 2-register operand order: VRB, VRT */
		o1 = AOP_RR(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg))

	case 86: /* VSX indexed store, XX1-form */
		/* reg reg reg */
		/* 3-register operand order: XT, (RB)(RA*1) */
		o1 = AOP_XX1(c.opstorex(p.As), uint32(p.From.Reg), uint32(p.To.Index), uint32(p.To.Reg))

	case 87: /* VSX indexed load, XX1-form */
		/* reg reg reg */
		/* 3-register operand order: (RB)(RA*1), XT */
		o1 = AOP_XX1(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))

	case 88: /* VSX mfvsr* instructions, XX1-form XS,RA */
		o1 = AOP_XX1(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))

	case 89: /* VSX instructions, XX2-form */
		/* reg none reg OR reg imm reg */
		/* 2-register operand order: XB, XT or XB, UIM, XT*/
		uim := int(c.regoff(p.GetFrom3()))
		o1 = AOP_XX2(c.oprrr(p.As), uint32(p.To.Reg), uint32(uim), uint32(p.From.Reg))

	case 90: /* VSX instructions, XX3-form */
		if p.From3Type() == obj.TYPE_NONE {
			/* reg reg reg */
			/* 3-register operand order: XA, XB, XT */
			o1 = AOP_XX3(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
		} else if p.From3Type() == obj.TYPE_CONST {
			/* reg reg reg imm */
			/* operand order: XA, XB, DM, XT */
			dm := int(c.regoff(p.GetFrom3()))
			o1 = AOP_XX3I(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(dm))
		}

	case 91: /* VSX instructions, XX4-form */
		/* reg reg reg reg */
		/* 3-register operand order: XA, XB, XC, XT */
		o1 = AOP_XX4(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(p.GetFrom3().Reg))

	case 92: /* X-form instructions, 3-operands */
		if p.To.Type == obj.TYPE_CONST {
			/* imm reg reg */
			xf := int32(p.From.Reg)
			if REG_F0 <= xf && xf <= REG_F31 {
				/* operand order: FRA, FRB, BF */
				bf := int(c.regoff(&p.To)) << 2
				o1 = AOP_RRR(c.opirr(p.As), uint32(bf), uint32(p.From.Reg), uint32(p.Reg))
			} else {
				/* operand order: RA, RB, L */
				l := int(c.regoff(&p.To))
				o1 = AOP_RRR(c.opirr(p.As), uint32(l), uint32(p.From.Reg), uint32(p.Reg))
			}
		} else if p.From3Type() == obj.TYPE_CONST {
			/* reg reg imm */
			/* operand order: RB, L, RA */
			l := int(c.regoff(p.GetFrom3()))
			o1 = AOP_RRR(c.opirr(p.As), uint32(l), uint32(p.To.Reg), uint32(p.From.Reg))
		} else if p.To.Type == obj.TYPE_REG {
			cr := int32(p.To.Reg)
			if REG_CR0 <= cr && cr <= REG_CR7 {
				/* cr reg reg */
				/* operand order: RA, RB, BF */
				bf := (int(p.To.Reg) & 7) << 2
				o1 = AOP_RRR(c.opirr(p.As), uint32(bf), uint32(p.From.Reg), uint32(p.Reg))
			} else if p.From.Type == obj.TYPE_CONST {
				/* reg imm */
				/* operand order: L, RT */
				l := int(c.regoff(&p.From))
				o1 = AOP_RRR(c.opirr(p.As), uint32(p.To.Reg), uint32(l), uint32(p.Reg))
			} else {
				switch p.As {
				case ACOPY, APASTECC:
					o1 = AOP_RRR(c.opirr(p.As), uint32(1), uint32(p.From.Reg), uint32(p.To.Reg))
				default:
					/* reg reg reg */
					/* operand order: RS, RB, RA */
					o1 = AOP_RRR(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
				}
			}
		}

	case 93: /* X-form instructions, 2-operands */
		if p.To.Type == obj.TYPE_CONST {
			/* imm reg */
			/* operand order: FRB, BF */
			bf := int(c.regoff(&p.To)) << 2
			o1 = AOP_RR(c.opirr(p.As), uint32(bf), uint32(p.From.Reg))
		} else if p.Reg == 0 {
			/* popcnt* r,r, X-form */
			/* operand order: RS, RA */
			o1 = AOP_RRR(c.oprrr(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(p.Reg))
		}

	case 94: /* Z23-form instructions, 4-operands */
		/* reg reg reg imm */
		/* operand order: RA, RB, CY, RT */
		cy := int(c.regoff(p.GetFrom3()))
		o1 = AOP_Z23I(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(cy))

	case 96: /* VSX load, DQ-form */
		/* reg imm reg */
		/* operand order: (RA)(DQ), XT */
		dq := int16(c.regoff(&p.From))
		if (dq & 15) != 0 {
			c.ctxt.Diag("invalid offset for DQ form load/store %v", dq)
		}
		o1 = AOP_DQ(c.opload(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(dq))

	case 97: /* VSX store, DQ-form */
		/* reg imm reg */
		/* operand order: XT, (RA)(DQ) */
		dq := int16(c.regoff(&p.To))
		if (dq & 15) != 0 {
			c.ctxt.Diag("invalid offset for DQ form load/store %v", dq)
		}
		o1 = AOP_DQ(c.opstore(p.As), uint32(p.From.Reg), uint32(p.To.Reg), uint32(dq))
	case 98: /* VSX indexed load or load with length (also left-justified), x-form */
		/* vsreg, reg, reg */
		o1 = AOP_XX1(c.opload(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))
	case 99: /* VSX store with length (also left-justified) x-form */
		/* reg, reg, vsreg */
		o1 = AOP_XX1(c.opstore(p.As), uint32(p.From.Reg), uint32(p.Reg), uint32(p.To.Reg))
	case 100: /* VSX X-form XXSPLTIB */
		if p.From.Type == obj.TYPE_CONST {
			/* imm reg */
			uim := int(c.regoff(&p.From))
			/* imm reg */
			/* Use AOP_XX1 form with 0 for one of the registers. */
			o1 = AOP_XX1(c.oprrr(p.As), uint32(p.To.Reg), uint32(0), uint32(uim))
		} else {
			c.ctxt.Diag("invalid ops for %v", p.As)
		}
	case 101:
		o1 = AOP_XX2(c.oprrr(p.As), uint32(p.To.Reg), uint32(0), uint32(p.From.Reg))

	case 104: /* VSX mtvsr* instructions, XX1-form RA,RB,XT */
		o1 = AOP_XX1(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg))

	case 106: /* MOVD spr, soreg */
		v := int32(p.From.Reg)
		o1 = OPVCC(31, 339, 0, 0) /* mfspr */
		o1 = AOP_RRR(o1, uint32(REGTMP), 0, 0) | (uint32(v)&0x1f)<<16 | ((uint32(v)>>5)&0x1f)<<11
		so := c.regoff(&p.To)
		o2 = AOP_IRR(c.opstore(AMOVD), uint32(REGTMP), uint32(p.To.Reg), uint32(so))
		if so&0x3 != 0 {
			log.Fatalf("invalid offset for DS form load/store %v", p)
		}
		if p.To.Reg == REGTMP {
			log.Fatalf("SPR move to memory will clobber R31 %v", p)
		}

	case 107: /* MOVD soreg, spr */
		v := int32(p.From.Reg)
		so := c.regoff(&p.From)
		o1 = AOP_IRR(c.opload(AMOVD), uint32(REGTMP), uint32(v), uint32(so))
		o2 = OPVCC(31, 467, 0, 0) /* mtspr */
		v = int32(p.To.Reg)
		o2 = AOP_RRR(o2, uint32(REGTMP), 0, 0) | (uint32(v)&0x1f)<<16 | ((uint32(v)>>5)&0x1f)<<11
		if so&0x3 != 0 {
			log.Fatalf("invalid offset for DS form load/store %v", p)
		}

	case 108: /* mov r, xoreg ==> stwx rx,ry */
		r := int(p.To.Reg)
		o1 = AOP_RRR(c.opstorex(p.As), uint32(p.From.Reg), uint32(p.To.Index), uint32(r))

	case 109: /* mov xoreg, r ==> lbzx/lhzx/lwzx rx,ry, lbzx rx,ry + extsb r,r */
		r := int(p.From.Reg)

		o1 = AOP_RRR(c.oploadx(p.As), uint32(p.To.Reg), uint32(p.From.Index), uint32(r))
		// Sign extend MOVB operations. This is ignored for other cases (o.size == 4).
		o2 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)

	case 110: /* SETB creg, rt */
		bfa := uint32(p.From.Reg) << 2
		rt := uint32(p.To.Reg)
		o1 = LOP_RRR(OP_SETB, bfa, rt, 0)
	}

	out[0] = o1
	out[1] = o2
	out[2] = o3
	out[3] = o4
	out[4] = o5
}

func (c *ctxt9) vregoff(a *obj.Addr) int64 {
	c.instoffset = 0
	if a != nil {
		c.aclass(a)
	}
	return c.instoffset
}

func (c *ctxt9) regoff(a *obj.Addr) int32 {
	return int32(c.vregoff(a))
}

func (c *ctxt9) oprrr(a obj.As) uint32 {
	switch a {
	case AADD:
		return OPVCC(31, 266, 0, 0)
	case AADDCC:
		return OPVCC(31, 266, 0, 1)
	case AADDV:
		return OPVCC(31, 266, 1, 0)
	case AADDVCC:
		return OPVCC(31, 266, 1, 1)
	case AADDC:
		return OPVCC(31, 10, 0, 0)
	case AADDCCC:
		return OPVCC(31, 10, 0, 1)
	case AADDCV:
		return OPVCC(31, 10, 1, 0)
	case AADDCVCC:
		return OPVCC(31, 10, 1, 1)
	case AADDE:
		return OPVCC(31, 138, 0, 0)
	case AADDECC:
		return OPVCC(31, 138, 0, 1)
	case AADDEV:
		return OPVCC(31, 138, 1, 0)
	case AADDEVCC:
		return OPVCC(31, 138, 1, 1)
	case AADDME:
		return OPVCC(31, 234, 0, 0)
	case AADDMECC:
		return OPVCC(31, 234, 0, 1)
	case AADDMEV:
		return OPVCC(31, 234, 1, 0)
	case AADDMEVCC:
		return OPVCC(31, 234, 1, 1)
	case AADDZE:
		return OPVCC(31, 202, 0, 0)
	case AADDZECC:
		return OPVCC(31, 202, 0, 1)
	case AADDZEV:
		return OPVCC(31, 202, 1, 0)
	case AADDZEVCC:
		return OPVCC(31, 202, 1, 1)
	case AADDEX:
		return OPVCC(31, 170, 0, 0) /* addex - v3.0b */

	case AAND:
		return OPVCC(31, 28, 0, 0)
	case AANDCC:
		return OPVCC(31, 28, 0, 1)
	case AANDN:
		return OPVCC(31, 60, 0, 0)
	case AANDNCC:
		return OPVCC(31, 60, 0, 1)

	case ACMP:
		return OPVCC(31, 0, 0, 0) | 1<<21 /* L=1 */
	case ACMPU:
		return OPVCC(31, 32, 0, 0) | 1<<21
	case ACMPW:
		return OPVCC(31, 0, 0, 0) /* L=0 */
	case ACMPWU:
		return OPVCC(31, 32, 0, 0)
	case ACMPB:
		return OPVCC(31, 508, 0, 0) /* cmpb - v2.05 */
	case ACMPEQB:
		return OPVCC(31, 224, 0, 0) /* cmpeqb - v3.00 */

	case ACNTLZW:
		return OPVCC(31, 26, 0, 0)
	case ACNTLZWCC:
		return OPVCC(31, 26, 0, 1)
	case ACNTLZD:
		return OPVCC(31, 58, 0, 0)
	case ACNTLZDCC:
		return OPVCC(31, 58, 0, 1)

	case ACRAND:
		return OPVCC(19, 257, 0, 0)
	case ACRANDN:
		return OPVCC(19, 129, 0, 0)
	case ACREQV:
		return OPVCC(19, 289, 0, 0)
	case ACRNAND:
		return OPVCC(19, 225, 0, 0)
	case ACRNOR:
		return OPVCC(19, 33, 0, 0)
	case ACROR:
		return OPVCC(19, 449, 0, 0)
	case ACRORN:
		return OPVCC(19, 417, 0, 0)
	case ACRXOR:
		return OPVCC(19, 193, 0, 0)

	case ADADD:
		return OPVCC(59, 2, 0, 0)
	case ADDIV:
		return OPVCC(59, 546, 0, 0)
	case ADMUL:
		return OPVCC(59, 34, 0, 0)
	case ADSUB:
		return OPVCC(59, 514, 0, 0)
	case ADADDQ:
		return OPVCC(63, 2, 0, 0)
	case ADDIVQ:
		return OPVCC(63, 546, 0, 0)
	case ADMULQ:
		return OPVCC(63, 34, 0, 0)
	case ADSUBQ:
		return OPVCC(63, 514, 0, 0)
	case ADCMPU:
		return OPVCC(59, 642, 0, 0)
	case ADCMPUQ:
		return OPVCC(63, 642, 0, 0)
	case ADCMPO:
		return OPVCC(59, 130, 0, 0)
	case ADCMPOQ:
		return OPVCC(63, 130, 0, 0)

	case ADCBF:
		return OPVCC(31, 86, 0, 0)
	case ADCBI:
		return OPVCC(31, 470, 0, 0)
	case ADCBST:
		return OPVCC(31, 54, 0, 0)
	case ADCBT:
		return OPVCC(31, 278, 0, 0)
	case ADCBTST:
		return OPVCC(31, 246, 0, 0)
	case ADCBZ:
		return OPVCC(31, 1014, 0, 0)

	case AMODUD:
		return OPVCC(31, 265, 0, 0) /* modud - v3.0 */
	case AMODUW:
		return OPVCC(31, 267, 0, 0) /* moduw - v3.0 */
	case AMODSD:
		return OPVCC(31, 777, 0, 0) /* modsd - v3.0 */
	case AMODSW:
		return OPVCC(31, 779, 0, 0) /* modsw - v3.0 */

	case ADIVW, AREM:
		return OPVCC(31, 491, 0, 0)

	case ADIVWCC:
		return OPVCC(31, 491, 0, 1)

	case ADIVWV:
		return OPVCC(31, 491, 1, 0)

	case ADIVWVCC:
		return OPVCC(31, 491, 1, 1)

	case ADIVWU, AREMU:
		return OPVCC(31, 459, 0, 0)

	case ADIVWUCC:
		return OPVCC(31, 459, 0, 1)

	case ADIVWUV:
		return OPVCC(31, 459, 1, 0)

	case ADIVWUVCC:
		return OPVCC(31, 459, 1, 1)

	case ADIVD, AREMD:
		return OPVCC(31, 489, 0, 0)

	case ADIVDCC:
		return OPVCC(31, 489, 0, 1)

	case ADIVDE:
		return OPVCC(31, 425, 0, 0)

	case ADIVDECC:
		return OPVCC(31, 425, 0, 1)

	case ADIVDEU:
		return OPVCC(31, 393, 0, 0)

	case ADIVDEUCC:
		return OPVCC(31, 393, 0, 1)

	case ADIVDV:
		return OPVCC(31, 489, 1, 0)

	case ADIVDVCC:
		return OPVCC(31, 489, 1, 1)

	case ADIVDU, AREMDU:
		return OPVCC(31, 457, 0, 0)

	case ADIVDUCC:
		return OPVCC(31, 457, 0, 1)

	case ADIVDUV:
		return OPVCC(31, 457, 1, 0)

	case ADIVDUVCC:
		return OPVCC(31, 457, 1, 1)

	case AEIEIO:
		return OPVCC(31, 854, 0, 0)

	case AEQV:
		return OPVCC(31, 284, 0, 0)
	case AEQVCC:
		return OPVCC(31, 284, 0, 1)

	case AEXTSB:
		return OPVCC(31, 954, 0, 0)
	case AEXTSBCC:
		return OPVCC(31, 954, 0, 1)
	case AEXTSH:
		return OPVCC(31, 922, 0, 0)
	case AEXTSHCC:
		return OPVCC(31, 922, 0, 1)
	case AEXTSW:
		return OPVCC(31, 986, 0, 0)
	case AEXTSWCC:
		return OPVCC(31, 986, 0, 1)

	case AFABS:
		return OPVCC(63, 264, 0, 0)
	case AFABSCC:
		return OPVCC(63, 264, 0, 1)
	case AFADD:
		return OPVCC(63, 21, 0, 0)
	case AFADDCC:
		return OPVCC(63, 21, 0, 1)
	case AFADDS:
		return OPVCC(59, 21, 0, 0)
	case AFADDSCC:
		return OPVCC(59, 21, 0, 1)
	case AFCMPO:
		return OPVCC(63, 32, 0, 0)
	case AFCMPU:
		return OPVCC(63, 0, 0, 0)
	case AFCFID:
		return OPVCC(63, 846, 0, 0)
	case AFCFIDCC:
		return OPVCC(63, 846, 0, 1)
	case AFCFIDU:
		return OPVCC(63, 974, 0, 0)
	case AFCFIDUCC:
		return OPVCC(63, 974, 0, 1)
	case AFCFIDS:
		return OPVCC(59, 846, 0, 0)
	case AFCFIDSCC:
		return OPVCC(59, 846, 0, 1)
	case AFCTIW:
		return OPVCC(63, 14, 0, 0)
	case AFCTIWCC:
		return OPVCC(63, 14, 0, 1)
	case AFCTIWZ:
		return OPVCC(63, 15, 0, 0)
	case AFCTIWZCC:
		return OPVCC(63, 15, 0, 1)
	case AFCTID:
		return OPVCC(63, 814, 0, 0)
	case AFCTIDCC:
		return OPVCC(63, 814, 0, 1)
	case AFCTIDZ:
		return OPVCC(63, 815, 0, 0)
	case AFCTIDZCC:
		return OPVCC(63, 815, 0, 1)
	case AFDIV:
		return OPVCC(63, 18, 0, 0)
	case AFDIVCC:
		return OPVCC(63, 18, 0, 1)
	case AFDIVS:
		return OPVCC(59, 18, 0, 0)
	case AFDIVSCC:
		return OPVCC(59, 18, 0, 1)
	case AFMADD:
		return OPVCC(63, 29, 0, 0)
	case AFMADDCC:
		return OPVCC(63, 29, 0, 1)
	case AFMADDS:
		return OPVCC(59, 29, 0, 0)
	case AFMADDSCC:
		return OPVCC(59, 29, 0, 1)

	case AFMOVS, AFMOVD:
		return OPVCC(63, 72, 0, 0) /* load */
	case AFMOVDCC:
		return OPVCC(63, 72, 0, 1)
	case AFMSUB:
		return OPVCC(63, 28, 0, 0)
	case AFMSUBCC:
		return OPVCC(63, 28, 0, 1)
	case AFMSUBS:
		return OPVCC(59, 28, 0, 0)
	case AFMSUBSCC:
		return OPVCC(59, 28, 0, 1)
	case AFMUL:
		return OPVCC(63, 25, 0, 0)
	case AFMULCC:
		return OPVCC(63, 25, 0, 1)
	case AFMULS:
		return OPVCC(59, 25, 0, 0)
	case AFMULSCC:
		return OPVCC(59, 25, 0, 1)
	case AFNABS:
		return OPVCC(63, 136, 0, 0)
	case AFNABSCC:
		return OPVCC(63, 136, 0, 1)
	case AFNEG:
		return OPVCC(63, 40, 0, 0)
	case AFNEGCC:
		return OPVCC(63, 40, 0, 1)
	case AFNMADD:
		return OPVCC(63, 31, 0, 0)
	case AFNMADDCC:
		return OPVCC(63, 31, 0, 1)
	case AFNMADDS:
		return OPVCC(59, 31, 0, 0)
	case AFNMADDSCC:
		return OPVCC(59, 31, 0, 1)
	case AFNMSUB:
		return OPVCC(63, 30, 0, 0)
	case AFNMSUBCC:
		return OPVCC(63, 30, 0, 1)
	case AFNMSUBS:
		return OPVCC(59, 30, 0, 0)
	case AFNMSUBSCC:
		return OPVCC(59, 30, 0, 1)
	case AFCPSGN:
		return OPVCC(63, 8, 0, 0)
	case AFCPSGNCC:
		return OPVCC(63, 8, 0, 1)
	case AFRES:
		return OPVCC(59, 24, 0, 0)
	case AFRESCC:
		return OPVCC(59, 24, 0, 1)
	case AFRIM:
		return OPVCC(63, 488, 0, 0)
	case AFRIMCC:
		return OPVCC(63, 488, 0, 1)
	case AFRIP:
		return OPVCC(63, 456, 0, 0)
	case AFRIPCC:
		return OPVCC(63, 456, 0, 1)
	case AFRIZ:
		return OPVCC(63, 424, 0, 0)
	case AFRIZCC:
		return OPVCC(63, 424, 0, 1)
	case AFRIN:
		return OPVCC(63, 392, 0, 0)
	case AFRINCC:
		return OPVCC(63, 392, 0, 1)
	case AFRSP:
		return OPVCC(63, 12, 0, 0)
	case AFRSPCC:
		return OPVCC(63, 12, 0, 1)
	case AFRSQRTE:
		return OPVCC(63, 26, 0, 0)
	case AFRSQRTECC:
		return OPVCC(63, 26, 0, 1)
	case AFSEL:
		return OPVCC(63, 23, 0, 0)
	case AFSELCC:
		return OPVCC(63, 23, 0, 1)
	case AFSQRT:
		return OPVCC(63, 22, 0, 0)
	case AFSQRTCC:
		return OPVCC(63, 22, 0, 1)
	case AFSQRTS:
		return OPVCC(59, 22, 0, 0)
	case AFSQRTSCC:
		return OPVCC(59, 22, 0, 1)
	case AFSUB:
		return OPVCC(63, 20, 0, 0)
	case AFSUBCC:
		return OPVCC(63, 20, 0, 1)
	case AFSUBS:
		return OPVCC(59, 20, 0, 0)
	case AFSUBSCC:
		return OPVCC(59, 20, 0, 1)

	case AICBI:
		return OPVCC(31, 982, 0, 0)
	case AISYNC:
		return OPVCC(19, 150, 0, 0)

	case AMTFSB0:
		return OPVCC(63, 70, 0, 0)
	case AMTFSB0CC:
		return OPVCC(63, 70, 0, 1)
	case AMTFSB1:
		return OPVCC(63, 38, 0, 0)
	case AMTFSB1CC:
		return OPVCC(63, 38, 0, 1)

	case AMULHW:
		return OPVCC(31, 75, 0, 0)
	case AMULHWCC:
		return OPVCC(31, 75, 0, 1)
	case AMULHWU:
		return OPVCC(31, 11, 0, 0)
	case AMULHWUCC:
		return OPVCC(31, 11, 0, 1)
	case AMULLW:
		return OPVCC(31, 235, 0, 0)
	case AMULLWCC:
		return OPVCC(31, 235, 0, 1)
	case AMULLWV:
		return OPVCC(31, 235, 1, 0)
	case AMULLWVCC:
		return OPVCC(31, 235, 1, 1)

	case AMULHD:
		return OPVCC(31, 73, 0, 0)
	case AMULHDCC:
		return OPVCC(31, 73, 0, 1)
	case AMULHDU:
		return OPVCC(31, 9, 0, 0)
	case AMULHDUCC:
		return OPVCC(31, 9, 0, 1)
	case AMULLD:
		return OPVCC(31, 233, 0, 0)
	case AMULLDCC:
		return OPVCC(31, 233, 0, 1)
	case AMULLDV:
		return OPVCC(31, 233, 1, 0)
	case AMULLDVCC:
		return OPVCC(31, 233, 1, 1)

	case ANAND:
		return OPVCC(31, 476, 0, 0)
	case ANANDCC:
		return OPVCC(31, 476, 0, 1)
	case ANEG:
		return OPVCC(31, 104, 0, 0)
	case ANEGCC:
		return OPVCC(31, 104, 0, 1)
	case ANEGV:
		return OPVCC(31, 104, 1, 0)
	case ANEGVCC:
		return OPVCC(31, 104, 1, 1)
	case ANOR:
		return OPVCC(31, 124, 0, 0)
	case ANORCC:
		return OPVCC(31, 124, 0, 1)
	case AOR:
		return OPVCC(31, 444, 0, 0)
	case AORCC:
		return OPVCC(31, 444, 0, 1)
	case AORN:
		return OPVCC(31, 412, 0, 0)
	case AORNCC:
		return OPVCC(31, 412, 0, 1)

	case APOPCNTD:
		return OPVCC(31, 506, 0, 0) /* popcntd - v2.06 */
	case APOPCNTW:
		return OPVCC(31, 378, 0, 0) /* popcntw - v2.06 */
	case APOPCNTB:
		return OPVCC(31, 122, 0, 0) /* popcntb - v2.02 */
	case ACNTTZW:
		return OPVCC(31, 538, 0, 0) /* cnttzw - v3.00 */
	case ACNTTZWCC:
		return OPVCC(31, 538, 0, 1) /* cnttzw. - v3.00 */
	case ACNTTZD:
		return OPVCC(31, 570, 0, 0) /* cnttzd - v3.00 */
	case ACNTTZDCC:
		return OPVCC(31, 570, 0, 1) /* cnttzd. - v3.00 */

	case ARFI:
		return OPVCC(19, 50, 0, 0)
	case ARFCI:
		return OPVCC(19, 51, 0, 0)
	case ARFID:
		return OPVCC(19, 18, 0, 0)
	case AHRFID:
		return OPVCC(19, 274, 0, 0)

	case ARLWNM:
		return OPVCC(23, 0, 0, 0)
	case ARLWNMCC:
		return OPVCC(23, 0, 0, 1)

	case ARLDCL:
		return OPVCC(30, 8, 0, 0)
	case ARLDCLCC:
		return OPVCC(30, 0, 0, 1)

	case ARLDCR:
		return OPVCC(30, 9, 0, 0)
	case ARLDCRCC:
		return OPVCC(30, 9, 0, 1)

	case ARLDICL:
		return OPVCC(30, 0, 0, 0)
	case ARLDICLCC:
		return OPVCC(30, 0, 0, 1)
	case ARLDICR:
		return OPMD(30, 1, 0) // rldicr
	case ARLDICRCC:
		return OPMD(30, 1, 1) // rldicr.

	case ARLDIC:
		return OPMD(30, 2, 0) // rldic
	case ARLDICCC:
		return OPMD(30, 2, 1) // rldic.

	case ASYSCALL:
		return OPVCC(17, 1, 0, 0)

	case ASLW:
		return OPVCC(31, 24, 0, 0)
	case ASLWCC:
		return OPVCC(31, 24, 0, 1)
	case ASLD:
		return OPVCC(31, 27, 0, 0)
	case ASLDCC:
		return OPVCC(31, 27, 0, 1)

	case ASRAW:
		return OPVCC(31, 792, 0, 0)
	case ASRAWCC:
		return OPVCC(31, 792, 0, 1)
	case ASRAD:
		return OPVCC(31, 794, 0, 0)
	case ASRADCC:
		return OPVCC(31, 794, 0, 1)

	case AEXTSWSLI:
		return OPVCC(31, 445, 0, 0)
	case AEXTSWSLICC:
		return OPVCC(31, 445, 0, 1)

	case ASRW:
		return OPVCC(31, 536, 0, 0)
	case ASRWCC:
		return OPVCC(31, 536, 0, 1)
	case ASRD:
		return OPVCC(31, 539, 0, 0)
	case ASRDCC:
		return OPVCC(31, 539, 0, 1)

	case ASUB:
		return OPVCC(31, 40, 0, 0)
	case ASUBCC:
		return OPVCC(31, 40, 0, 1)
	case ASUBV:
		return OPVCC(31, 40, 1, 0)
	case ASUBVCC:
		return OPVCC(31, 40, 1, 1)
	case ASUBC:
		return OPVCC(31, 8, 0, 0)
	case ASUBCCC:
		return OPVCC(31, 8, 0, 1)
	case ASUBCV:
		return OPVCC(31, 8, 1, 0)
	case ASUBCVCC:
		return OPVCC(31, 8, 1, 1)
	case ASUBE:
		return OPVCC(31, 136, 0, 0)
	case ASUBECC:
		return OPVCC(31, 136, 0, 1)
	case ASUBEV:
		return OPVCC(31, 136, 1, 0)
	case ASUBEVCC:
		return OPVCC(31, 136, 1, 1)
	case ASUBME:
		return OPVCC(31, 232, 0, 0)
	case ASUBMECC:
		return OPVCC(31, 232, 0, 1)
	case ASUBMEV:
		return OPVCC(31, 232, 1, 0)
	case ASUBMEVCC:
		return OPVCC(31, 232, 1, 1)
	case ASUBZE:
		return OPVCC(31, 200, 0, 0)
	case ASUBZECC:
		return OPVCC(31, 200, 0, 1)
	case ASUBZEV:
		return OPVCC(31, 200, 1, 0)
	case ASUBZEVCC:
		return OPVCC(31, 200, 1, 1)

	case ASYNC:
		return OPVCC(31, 598, 0, 0)
	case ALWSYNC:
		return OPVCC(31, 598, 0, 0) | 1<<21

	case APTESYNC:
		return OPVCC(31, 598, 0, 0) | 2<<21

	case ATLBIE:
		return OPVCC(31, 306, 0, 0)
	case ATLBIEL:
		return OPVCC(31, 274, 0, 0)
	case ATLBSYNC:
		return OPVCC(31, 566, 0, 0)
	case ASLBIA:
		return OPVCC(31, 498, 0, 0)
	case ASLBIE:
		return OPVCC(31, 434, 0, 0)
	case ASLBMFEE:
		return OPVCC(31, 915, 0, 0)
	case ASLBMFEV:
		return OPVCC(31, 851, 0, 0)
	case ASLBMTE:
		return OPVCC(31, 402, 0, 0)

	case ATW:
		return OPVCC(31, 4, 0, 0)
	case ATD:
		return OPVCC(31, 68, 0, 0)

	/* Vector (VMX/Altivec) instructions */
	/* ISA 2.03 enables these for PPC970. For POWERx processors, these */
	/* are enabled starting at POWER6 (ISA 2.05). */
	case AVAND:
		return OPVX(4, 1028, 0, 0) /* vand - v2.03 */
	case AVANDC:
		return OPVX(4, 1092, 0, 0) /* vandc - v2.03 */
	case AVNAND:
		return OPVX(4, 1412, 0, 0) /* vnand - v2.07 */

	case AVOR:
		return OPVX(4, 1156, 0, 0) /* vor - v2.03 */
	case AVORC:
		return OPVX(4, 1348, 0, 0) /* vorc - v2.07 */
	case AVNOR:
		return OPVX(4, 1284, 0, 0) /* vnor - v2.03 */
	case AVXOR:
		return OPVX(4, 1220, 0, 0) /* vxor - v2.03 */
	case AVEQV:
		return OPVX(4, 1668, 0, 0) /* veqv - v2.07 */

	case AVADDUBM:
		return OPVX(4, 0, 0, 0) /* vaddubm - v2.03 */
	case AVADDUHM:
		return OPVX(4, 64, 0, 0) /* vadduhm - v2.03 */
	case AVADDUWM:
		return OPVX(4, 128, 0, 0) /* vadduwm - v2.03 */
	case AVADDUDM:
		return OPVX(4, 192, 0, 0) /* vaddudm - v2.07 */
	case AVADDUQM:
		return OPVX(4, 256, 0, 0) /* vadduqm - v2.07 */

	case AVADDCUQ:
		return OPVX(4, 320, 0, 0) /* vaddcuq - v2.07 */
	case AVADDCUW:
		return OPVX(4, 384, 0, 0) /* vaddcuw - v2.03 */

	case AVADDUBS:
		return OPVX(4, 512, 0, 0) /* vaddubs - v2.03 */
	case AVADDUHS:
		return OPVX(4, 576, 0, 0) /* vadduhs - v2.03 */
	case AVADDUWS:
		return OPVX(4, 640, 0, 0) /* vadduws - v2.03 */

	case AVADDSBS:
		return OPVX(4, 768, 0, 0) /* vaddsbs - v2.03 */
	case AVADDSHS:
		return OPVX(4, 832, 0, 0) /* vaddshs - v2.03 */
	case AVADDSWS:
		return OPVX(4, 896, 0, 0) /* vaddsws - v2.03 */

	case AVADDEUQM:
		return OPVX(4, 60, 0, 0) /* vaddeuqm - v2.07 */
	case AVADDECUQ:
		return OPVX(4, 61, 0, 0) /* vaddecuq - v2.07 */

	case AVMULESB:
		return OPVX(4, 776, 0, 0) /* vmulesb - v2.03 */
	case AVMULOSB:
		return OPVX(4, 264, 0, 0) /* vmulosb - v2.03 */
	case AVMULEUB:
		return OPVX(4, 520, 0, 0) /* vmuleub - v2.03 */
	case AVMULOUB:
		return OPVX(4, 8, 0, 0) /* vmuloub - v2.03 */
	case AVMULESH:
		return OPVX(4, 840, 0, 0) /* vmulesh - v2.03 */
	case AVMULOSH:
		return OPVX(4, 328, 0, 0) /* vmulosh - v2.03 */
	case AVMULEUH:
		return OPVX(4, 584, 0, 0) /* vmuleuh - v2.03 */
	case AVMULOUH:
		return OPVX(4, 72, 0, 0) /* vmulouh - v2.03 */
	case AVMULESW:
		return OPVX(4, 904, 0, 0) /* vmulesw - v2.07 */
	case AVMULOSW:
		return OPVX(4, 392, 0, 0) /* vmulosw - v2.07 */
	case AVMULEUW:
		return OPVX(4, 648, 0, 0) /* vmuleuw - v2.07 */
	case AVMULOUW:
		return OPVX(4, 136, 0, 0) /* vmulouw - v2.07 */
	case AVMULUWM:
		return OPVX(4, 137, 0, 0) /* vmuluwm - v2.07 */

	case AVPMSUMB:
		return OPVX(4, 1032, 0, 0) /* vpmsumb - v2.07 */
	case AVPMSUMH:
		return OPVX(4, 1096, 0, 0) /* vpmsumh - v2.07 */
	case AVPMSUMW:
		return OPVX(4, 1160, 0, 0) /* vpmsumw - v2.07 */
	case AVPMSUMD:
		return OPVX(4, 1224, 0, 0) /* vpmsumd - v2.07 */

	case AVMSUMUDM:
		return OPVX(4, 35, 0, 0) /* vmsumudm - v3.00b */

	case AVSUBUBM:
		return OPVX(4, 1024, 0, 0) /* vsububm - v2.03 */
	case AVSUBUHM:
		return OPVX(4, 1088, 0, 0) /* vsubuhm - v2.03 */
	case AVSUBUWM:
		return OPVX(4, 1152, 0, 0) /* vsubuwm - v2.03 */
	case AVSUBUDM:
		return OPVX(4, 1216, 0, 0) /* vsubudm - v2.07 */
	case AVSUBUQM:
		return OPVX(4, 1280, 0, 0) /* vsubuqm - v2.07 */

	case AVSUBCUQ:
		return OPVX(4, 1344, 0, 0) /* vsubcuq - v2.07 */
	case AVSUBCUW:
		return OPVX(4, 1408, 0, 0) /* vsubcuw - v2.03 */

	case AVSUBUBS:
		return OPVX(4, 1536, 0, 0) /* vsububs - v2.03 */
	case AVSUBUHS:
		return OPVX(4, 1600, 0, 0) /* vsubuhs - v2.03 */
	case AVSUBUWS:
		return OPVX(4, 1664, 0, 0) /* vsubuws - v2.03 */

	case AVSUBSBS:
		return OPVX(4, 1792, 0, 0) /* vsubsbs - v2.03 */
	case AVSUBSHS:
		return OPVX(4, 1856, 0, 0) /* vsubshs - v2.03 */
	case AVSUBSWS:
		return OPVX(4, 1920, 0, 0) /* vsubsws - v2.03 */

	case AVSUBEUQM:
		return OPVX(4, 62, 0, 0) /* vsubeuqm - v2.07 */
	case AVSUBECUQ:
		return OPVX(4, 63, 0, 0) /* vsubecuq - v2.07 */

	case AVRLB:
		return OPVX(4, 4, 0, 0) /* vrlb - v2.03 */
	case AVRLH:
		return OPVX(4, 68, 0, 0) /* vrlh - v2.03 */
	case AVRLW:
		return OPVX(4, 132, 0, 0) /* vrlw - v2.03 */
	case AVRLD:
		return OPVX(4, 196, 0, 0) /* vrld - v2.07 */

	case AVMRGOW:
		return OPVX(4, 1676, 0, 0) /* vmrgow - v2.07 */
	case AVMRGEW:
		return OPVX(4, 1932, 0, 0) /* vmrgew - v2.07 */

	case AVSLB:
		return OPVX(4, 260, 0, 0) /* vslh - v2.03 */
	case AVSLH:
		return OPVX(4, 324, 0, 0) /* vslh - v2.03 */
	case AVSLW:
		return OPVX(4, 388, 0, 0) /* vslw - v2.03 */
	case AVSL:
		return OPVX(4, 452, 0, 0) /* vsl - v2.03 */
	case AVSLO:
		return OPVX(4, 1036, 0, 0) /* vsl - v2.03 */
	case AVSRB:
		return OPVX(4, 516, 0, 0) /* vsrb - v2.03 */
	case AVSRH:
		return OPVX(4, 580, 0, 0) /* vsrh - v2.03 */
	case AVSRW:
		return OPVX(4, 644, 0, 0) /* vsrw - v2.03 */
	case AVSR:
		return OPVX(4, 708, 0, 0) /* vsr - v2.03 */
	case AVSRO:
		return OPVX(4, 1100, 0, 0) /* vsro - v2.03 */
	case AVSLD:
		return OPVX(4, 1476, 0, 0) /* vsld - v2.07 */
	case AVSRD:
		return OPVX(4, 1732, 0, 0) /* vsrd - v2.07 */

	case AVSRAB:
		return OPVX(4, 772, 0, 0) /* vsrab - v2.03 */
	case AVSRAH:
		return OPVX(4, 836, 0, 0) /* vsrah - v2.03 */
	case AVSRAW:
		return OPVX(4, 900, 0, 0) /* vsraw - v2.03 */
	case AVSRAD:
		return OPVX(4, 964, 0, 0) /* vsrad - v2.07 */

	case AVBPERMQ:
		return OPVC(4, 1356, 0, 0) /* vbpermq - v2.07 */
	case AVBPERMD:
		return OPVC(4, 1484, 0, 0) /* vbpermd - v3.00 */

	case AVCLZB:
		return OPVX(4, 1794, 0, 0) /* vclzb - v2.07 */
	case AVCLZH:
		return OPVX(4, 1858, 0, 0) /* vclzh - v2.07 */
	case AVCLZW:
		return OPVX(4, 1922, 0, 0) /* vclzw - v2.07 */
	case AVCLZD:
		return OPVX(4, 1986, 0, 0) /* vclzd - v2.07 */

	case AVCLZLSBB:
		return OPVX(4, 1538, 0, 0) /* vclzlsbb - v3.0 */
	case AVCTZLSBB:
		return OPVX(4, 1538, 0, 0) | 1<<16 /* vctzlsbb - v3.0 */

	case AVPOPCNTB:
		return OPVX(4, 1795, 0, 0) /* vpopcntb - v2.07 */
	case AVPOPCNTH:
		return OPVX(4, 1859, 0, 0) /* vpopcnth - v2.07 */
	case AVPOPCNTW:
		return OPVX(4, 1923, 0, 0) /* vpopcntw - v2.07 */
	case AVPOPCNTD:
		return OPVX(4, 1987, 0, 0) /* vpopcntd - v2.07 */

	case AVCMPEQUB:
		return OPVC(4, 6, 0, 0) /* vcmpequb - v2.03 */
	case AVCMPEQUBCC:
		return OPVC(4, 6, 0, 1) /* vcmpequb. - v2.03 */
	case AVCMPEQUH:
		return OPVC(4, 70, 0, 0) /* vcmpequh - v2.03 */
	case AVCMPEQUHCC:
		return OPVC(4, 70, 0, 1) /* vcmpequh. - v2.03 */
	case AVCMPEQUW:
		return OPVC(4, 134, 0, 0) /* vcmpequw - v2.03 */
	case AVCMPEQUWCC:
		return OPVC(4, 134, 0, 1) /* vcmpequw. - v2.03 */
	case AVCMPEQUD:
		return OPVC(4, 199, 0, 0) /* vcmpequd - v2.07 */
	case AVCMPEQUDCC:
		return OPVC(4, 199, 0, 1) /* vcmpequd. - v2.07 */

	case AVCMPGTUB:
		return OPVC(4, 518, 0, 0) /* vcmpgtub - v2.03 */
	case AVCMPGTUBCC:
		return OPVC(4, 518, 0, 1) /* vcmpgtub. - v2.03 */
	case AVCMPGTUH:
		return OPVC(4, 582, 0, 0) /* vcmpgtuh - v2.03 */
	case AVCMPGTUHCC:
		return OPVC(4, 582, 0, 1) /* vcmpgtuh. - v2.03 */
	case AVCMPGTUW:
		return OPVC(4, 646, 0, 0) /* vcmpgtuw - v2.03 */
	case AVCMPGTUWCC:
		return OPVC(4, 646, 0, 1) /* vcmpgtuw. - v2.03 */
	case AVCMPGTUD:
		return OPVC(4, 711, 0, 0) /* vcmpgtud - v2.07 */
	case AVCMPGTUDCC:
		return OPVC(4, 711, 0, 1) /* vcmpgtud. v2.07 */
	case AVCMPGTSB:
		return OPVC(4, 774, 0, 0) /* vcmpgtsb - v2.03 */
	case AVCMPGTSBCC:
		return OPVC(4, 774, 0, 1) /* vcmpgtsb. - v2.03 */
	case AVCMPGTSH:
		return OPVC(4, 838, 0, 0) /* vcmpgtsh - v2.03 */
	case AVCMPGTSHCC:
		return OPVC(4, 838, 0, 1) /* vcmpgtsh. - v2.03 */
	case AVCMPGTSW:
		return OPVC(4, 902, 0, 0) /* vcmpgtsw - v2.03 */
	case AVCMPGTSWCC:
		return OPVC(4, 902, 0, 1) /* vcmpgtsw. - v2.03 */
	case AVCMPGTSD:
		return OPVC(4, 967, 0, 0) /* vcmpgtsd - v2.07 */
	case AVCMPGTSDCC:
		return OPVC(4, 967, 0, 1) /* vcmpgtsd. - v2.07 */

	case AVCMPNEZB:
		return OPVC(4, 263, 0, 0) /* vcmpnezb - v3.00 */
	case AVCMPNEZBCC:
		return OPVC(4, 263, 0, 1) /* vcmpnezb. - v3.00 */
	case AVCMPNEB:
		return OPVC(4, 7, 0, 0) /* vcmpneb - v3.00 */
	case AVCMPNEBCC:
		return OPVC(4, 7, 0, 1) /* vcmpneb. - v3.00 */
	case AVCMPNEH:
		return OPVC(4, 71, 0, 0) /* vcmpneh - v3.00 */
	case AVCMPNEHCC:
		return OPVC(4, 71, 0, 1) /* vcmpneh. - v3.00 */
	case AVCMPNEW:
		return OPVC(4, 135, 0, 0) /* vcmpnew - v3.00 */
	case AVCMPNEWCC:
		return OPVC(4, 135, 0, 1) /* vcmpnew. - v3.00 */

	case AVPERM:
		return OPVX(4, 43, 0, 0) /* vperm - v2.03 */
	case AVPERMXOR:
		return OPVX(4, 45, 0, 0) /* vpermxor - v2.03 */
	case AVPERMR:
		return OPVX(4, 59, 0, 0) /* vpermr - v3.0 */

	case AVSEL:
		return OPVX(4, 42, 0, 0) /* vsel - v2.03 */

	case AVCIPHER:
		return OPVX(4, 1288, 0, 0) /* vcipher - v2.07 */
	case AVCIPHERLAST:
		return OPVX(4, 1289, 0, 0) /* vcipherlast - v2.07 */
	case AVNCIPHER:
		return OPVX(4, 1352, 0, 0) /* vncipher - v2.07 */
	case AVNCIPHERLAST:
		return OPVX(4, 1353, 0, 0) /* vncipherlast - v2.07 */
	case AVSBOX:
		return OPVX(4, 1480, 0, 0) /* vsbox - v2.07 */
	/* End of vector instructions */

	/* Vector scalar (VSX) instructions */
	/* ISA 2.06 enables these for POWER7. */
	case AMFVSRD, AMFVRD, AMFFPRD:
		return OPVXX1(31, 51, 0) /* mfvsrd - v2.07 */
	case AMFVSRWZ:
		return OPVXX1(31, 115, 0) /* mfvsrwz - v2.07 */
	case AMFVSRLD:
		return OPVXX1(31, 307, 0) /* mfvsrld - v3.00 */

	case AMTVSRD, AMTFPRD, AMTVRD:
		return OPVXX1(31, 179, 0) /* mtvsrd - v2.07 */
	case AMTVSRWA:
		return OPVXX1(31, 211, 0) /* mtvsrwa - v2.07 */
	case AMTVSRWZ:
		return OPVXX1(31, 243, 0) /* mtvsrwz - v2.07 */
	case AMTVSRDD:
		return OPVXX1(31, 435, 0) /* mtvsrdd - v3.00 */
	case AMTVSRWS:
		return OPVXX1(31, 403, 0) /* mtvsrws - v3.00 */

	case AXXLAND:
		return OPVXX3(60, 130, 0) /* xxland - v2.06 */
	case AXXLANDC:
		return OPVXX3(60, 138, 0) /* xxlandc - v2.06 */
	case AXXLEQV:
		return OPVXX3(60, 186, 0) /* xxleqv - v2.07 */
	case AXXLNAND:
		return OPVXX3(60, 178, 0) /* xxlnand - v2.07 */

	case AXXLORC:
		return OPVXX3(60, 170, 0) /* xxlorc - v2.07 */
	case AXXLNOR:
		return OPVXX3(60, 162, 0) /* xxlnor - v2.06 */
	case AXXLOR, AXXLORQ:
		return OPVXX3(60, 146, 0) /* xxlor - v2.06 */
	case AXXLXOR:
		return OPVXX3(60, 154, 0) /* xxlxor - v2.06 */
	case AXSMINJDP:
		return OPVXX3(60, 152, 0) /* xsminjdp - v3.0 */
	case AXSMAXJDP:
		return OPVXX3(60, 144, 0) /* xsmaxjdp - v3.0 */

	case AXXSEL:
		return OPVXX4(60, 3, 0) /* xxsel - v2.06 */

	case AXXMRGHW:
		return OPVXX3(60, 18, 0) /* xxmrghw - v2.06 */
	case AXXMRGLW:
		return OPVXX3(60, 50, 0) /* xxmrglw - v2.06 */

	case AXXSPLTW:
		return OPVXX2(60, 164, 0) /* xxspltw - v2.06 */

	case AXXSPLTIB:
		return OPVCC(60, 360, 0, 0) /* xxspltib - v3.0 */

	case AXXPERM:
		return OPVXX3(60, 26, 0) /* xxperm - v2.06 */
	case AXXPERMDI:
		return OPVXX3(60, 10, 0) /* xxpermdi - v2.06 */

	case AXXSLDWI:
		return OPVXX3(60, 2, 0) /* xxsldwi - v2.06 */

	case AXXBRQ:
		return OPVXX2VA(60, 475, 31) /* xxbrq - v3.0 */
	case AXXBRD:
		return OPVXX2VA(60, 475, 23) /* xxbrd - v3.0 */
	case AXXBRW:
		return OPVXX2VA(60, 475, 15) /* xxbrw - v3.0 */
	case AXXBRH:
		return OPVXX2VA(60, 475, 7) /* xxbrh - v3.0 */

	case AXSCVDPSP:
		return OPVXX2(60, 265, 0) /* xscvdpsp - v2.06 */
	case AXSCVSPDP:
		return OPVXX2(60, 329, 0) /* xscvspdp - v2.06 */
	case AXSCVDPSPN:
		return OPVXX2(60, 267, 0) /* xscvdpspn - v2.07 */
	case AXSCVSPDPN:
		return OPVXX2(60, 331, 0) /* xscvspdpn - v2.07 */

	case AXVCVDPSP:
		return OPVXX2(60, 393, 0) /* xvcvdpsp - v2.06 */
	case AXVCVSPDP:
		return OPVXX2(60, 457, 0) /* xvcvspdp - v2.06 */

	case AXSCVDPSXDS:
		return OPVXX2(60, 344, 0) /* xscvdpsxds - v2.06 */
	case AXSCVDPSXWS:
		return OPVXX2(60, 88, 0) /* xscvdpsxws - v2.06 */
	case AXSCVDPUXDS:
		return OPVXX2(60, 328, 0) /* xscvdpuxds - v2.06 */
	case AXSCVDPUXWS:
		return OPVXX2(60, 72, 0) /* xscvdpuxws - v2.06 */

	case AXSCVSXDDP:
		return OPVXX2(60, 376, 0) /* xscvsxddp - v2.06 */
	case AXSCVUXDDP:
		return OPVXX2(60, 360, 0) /* xscvuxddp - v2.06 */
	case AXSCVSXDSP:
		return OPVXX2(60, 312, 0) /* xscvsxdsp - v2.06 */
	case AXSCVUXDSP:
		return OPVXX2(60, 296, 0) /* xscvuxdsp - v2.06 */

	case AXVCVDPSXDS:
		return OPVXX2(60, 472, 0) /* xvcvdpsxds - v2.06 */
	case AXVCVDPSXWS:
		return OPVXX2(60, 216, 0) /* xvcvdpsxws - v2.06 */
	case AXVCVDPUXDS:
		return OPVXX2(60, 456, 0) /* xvcvdpuxds - v2.06 */
	case AXVCVDPUXWS:
		return OPVXX2(60, 200, 0) /* xvcvdpuxws - v2.06 */
	case AXVCVSPSXDS:
		return OPVXX2(60, 408, 0) /* xvcvspsxds - v2.07 */
	case AXVCVSPSXWS:
		return OPVXX2(60, 152, 0) /* xvcvspsxws - v2.07 */
	case AXVCVSPUXDS:
		return OPVXX2(60, 392, 0) /* xvcvspuxds - v2.07 */
	case AXVCVSPUXWS:
		return OPVXX2(60, 136, 0) /* xvcvspuxws - v2.07 */

	case AXVCVSXDDP:
		return OPVXX2(60, 504, 0) /* xvcvsxddp - v2.06 */
	case AXVCVSXWDP:
		return OPVXX2(60, 248, 0) /* xvcvsxwdp - v2.06 */
	case AXVCVUXDDP:
		return OPVXX2(60, 488, 0) /* xvcvuxddp - v2.06 */
	case AXVCVUXWDP:
		return OPVXX2(60, 232, 0) /* xvcvuxwdp - v2.06 */
	case AXVCVSXDSP:
		return OPVXX2(60, 440, 0) /* xvcvsxdsp - v2.06 */
	case AXVCVSXWSP:
		return OPVXX2(60, 184, 0) /* xvcvsxwsp - v2.06 */
	case AXVCVUXDSP:
		return OPVXX2(60, 424, 0) /* xvcvuxdsp - v2.06 */
	case AXVCVUXWSP:
		return OPVXX2(60, 168, 0) /* xvcvuxwsp - v2.06 */
	/* End of VSX instructions */

	case AMADDHD:
		return OPVX(4, 48, 0, 0) /* maddhd - v3.00 */
	case AMADDHDU:
		return OPVX(4, 49, 0, 0) /* maddhdu - v3.00 */
	case AMADDLD:
		return OPVX(4, 51, 0, 0) /* maddld - v3.00 */

	case AXOR:
		return OPVCC(31, 316, 0, 0)
	case AXORCC:
		return OPVCC(31, 316, 0, 1)
	}

	c.ctxt.Diag("bad r/r, r/r/r or r/r/r/r opcode %v", a)
	return 0
}

func (c *ctxt9) opirrr(a obj.As) uint32 {
	switch a {
	/* Vector (VMX/Altivec) instructions */
	/* ISA 2.03 enables these for PPC970. For POWERx processors, these */
	/* are enabled starting at POWER6 (ISA 2.05). */
	case AVSLDOI:
		return OPVX(4, 44, 0, 0) /* vsldoi - v2.03 */
	}

	c.ctxt.Diag("bad i/r/r/r opcode %v", a)
	return 0
}

func (c *ctxt9) opiirr(a obj.As) uint32 {
	switch a {
	/* Vector (VMX/Altivec) instructions */
	/* ISA 2.07 enables these for POWER8 and beyond. */
	case AVSHASIGMAW:
		return OPVX(4, 1666, 0, 0) /* vshasigmaw - v2.07 */
	case AVSHASIGMAD:
		return OPVX(4, 1730, 0, 0) /* vshasigmad - v2.07 */
	}

	c.ctxt.Diag("bad i/i/r/r opcode %v", a)
	return 0
}

func (c *ctxt9) opirr(a obj.As) uint32 {
	switch a {
	case AADD:
		return OPVCC(14, 0, 0, 0)
	case AADDC:
		return OPVCC(12, 0, 0, 0)
	case AADDCCC:
		return OPVCC(13, 0, 0, 0)
	case AADDIS:
		return OPVCC(15, 0, 0, 0) /* ADDIS */

	case AANDCC:
		return OPVCC(28, 0, 0, 0)
	case AANDISCC:
		return OPVCC(29, 0, 0, 0) /* ANDIS. */

	case ABR:
		return OPVCC(18, 0, 0, 0)
	case ABL:
		return OPVCC(18, 0, 0, 0) | 1
	case obj.ADUFFZERO:
		return OPVCC(18, 0, 0, 0) | 1
	case obj.ADUFFCOPY:
		return OPVCC(18, 0, 0, 0) | 1
	case ABC:
		return OPVCC(16, 0, 0, 0)
	case ABCL:
		return OPVCC(16, 0, 0, 0) | 1

	case ABEQ:
		return AOP_RRR(16<<26, BO_BCR, BI_EQ, 0)
	case ABGE:
		return AOP_RRR(16<<26, BO_NOTBCR, BI_LT, 0)
	case ABGT:
		return AOP_RRR(16<<26, BO_BCR, BI_GT, 0)
	case ABLE:
		return AOP_RRR(16<<26, BO_NOTBCR, BI_GT, 0)
	case ABLT:
		return AOP_RRR(16<<26, BO_BCR, BI_LT, 0)
	case ABNE:
		return AOP_RRR(16<<26, BO_NOTBCR, BI_EQ, 0)
	case ABVC:
		return AOP_RRR(16<<26, BO_NOTBCR, BI_FU, 0)
	case ABVS:
		return AOP_RRR(16<<26, BO_BCR, BI_FU, 0)
	case ABDZ:
		return AOP_RRR(16<<26, BO_NOTBCTR, 0, 0)
	case ABDNZ:
		return AOP_RRR(16<<26, BO_BCTR, 0, 0)

	case ACMP:
		return OPVCC(11, 0, 0, 0) | 1<<21 /* L=1 */
	case ACMPU:
		return OPVCC(10, 0, 0, 0) | 1<<21
	case ACMPW:
		return OPVCC(11, 0, 0, 0) /* L=0 */
	case ACMPWU:
		return OPVCC(10, 0, 0, 0)
	case ACMPEQB:
		return OPVCC(31, 224, 0, 0) /* cmpeqb - v3.00 */

	case ALSW:
		return OPVCC(31, 597, 0, 0)

	case ACOPY:
		return OPVCC(31, 774, 0, 0) /* copy - v3.00 */
	case APASTECC:
		return OPVCC(31, 902, 0, 1) /* paste. - v3.00 */
	case ADARN:
		return OPVCC(31, 755, 0, 0) /* darn - v3.00 */

	case AMULLW, AMULLD:
		return OPVCC(7, 0, 0, 0) /* mulli works with MULLW or MULLD */

	case AOR:
		return OPVCC(24, 0, 0, 0)
	case AORIS:
		return OPVCC(25, 0, 0, 0) /* ORIS */

	case ARLWMI:
		return OPVCC(20, 0, 0, 0) /* rlwimi */
	case ARLWMICC:
		return OPVCC(20, 0, 0, 1)
	case ARLDMI:
		return OPMD(30, 3, 0) /* rldimi */
	case ARLDMICC:
		return OPMD(30, 3, 1) /* rldimi. */
	case ARLDIMI:
		return OPMD(30, 3, 0) /* rldimi */
	case ARLDIMICC:
		return OPMD(30, 3, 1) /* rldimi. */
	case ARLWNM:
		return OPVCC(21, 0, 0, 0) /* rlwinm */
	case ARLWNMCC:
		return OPVCC(21, 0, 0, 1)

	case ARLDCL:
		return OPMD(30, 0, 0) /* rldicl */
	case ARLDCLCC:
		return OPMD(30, 0, 1) /* rldicl. */
	case ARLDCR:
		return OPMD(30, 1, 0) /* rldicr */
	case ARLDCRCC:
		return OPMD(30, 1, 1) /* rldicr. */
	case ARLDC:
		return OPMD(30, 2, 0) /* rldic */
	case ARLDCCC:
		return OPMD(30, 2, 1) /* rldic. */

	case ASRAW:
		return OPVCC(31, 824, 0, 0)
	case ASRAWCC:
		return OPVCC(31, 824, 0, 1)
	case ASRAD:
		return OPVCC(31, (413 << 1), 0, 0)
	case ASRADCC:
		return OPVCC(31, (413 << 1), 0, 1)
	case AEXTSWSLI:
		return OPVCC(31, 445, 0, 0)
	case AEXTSWSLICC:
		return OPVCC(31, 445, 0, 1)

	case ASTSW:
		return OPVCC(31, 725, 0, 0)

	case ASUBC:
		return OPVCC(8, 0, 0, 0)

	case ATW:
		return OPVCC(3, 0, 0, 0)
	case ATD:
		return OPVCC(2, 0, 0, 0)

	/* Vector (VMX/Altivec) instructions */
	/* ISA 2.03 enables these for PPC970. For POWERx processors, these */
	/* are enabled starting at POWER6 (ISA 2.05). */
	case AVSPLTB:
		return OPVX(4, 524, 0, 0) /* vspltb - v2.03 */
	case AVSPLTH:
		return OPVX(4, 588, 0, 0) /* vsplth - v2.03 */
	case AVSPLTW:
		return OPVX(4, 652, 0, 0) /* vspltw - v2.03 */

	case AVSPLTISB:
		return OPVX(4, 780, 0, 0) /* vspltisb - v2.03 */
	case AVSPLTISH:
		return OPVX(4, 844, 0, 0) /* vspltish - v2.03 */
	case AVSPLTISW:
		return OPVX(4, 908, 0, 0) /* vspltisw - v2.03 */
	/* End of vector instructions */

	case AFTDIV:
		return OPVCC(63, 128, 0, 0) /* ftdiv - v2.06 */
	case AFTSQRT:
		return OPVCC(63, 160, 0, 0) /* ftsqrt - v2.06 */

	case AXOR:
		return OPVCC(26, 0, 0, 0) /* XORIL */
	case AXORIS:
		return OPVCC(27, 0, 0, 0) /* XORIS */
	}

	c.ctxt.Diag("bad opcode i/r or i/r/r %v", a)
	return 0
}

/*
 * load o(a),d
 */
func (c *ctxt9) opload(a obj.As) uint32 {
	switch a {
	case AMOVD:
		return OPVCC(58, 0, 0, 0) /* ld */
	case AMOVDU:
		return OPVCC(58, 0, 0, 1) /* ldu */
	case AMOVWZ:
		return OPVCC(32, 0, 0, 0) /* lwz */
	case AMOVWZU:
		return OPVCC(33, 0, 0, 0) /* lwzu */
	case AMOVW:
		return OPVCC(58, 0, 0, 0) | 1<<1 /* lwa */
	case ALXV:
		return OPDQ(61, 1, 0) /* lxv - ISA v3.0 */
	case ALXVL:
		return OPVXX1(31, 269, 0) /* lxvl - ISA v3.0 */
	case ALXVLL:
		return OPVXX1(31, 301, 0) /* lxvll - ISA v3.0 */
	case ALXVX:
		return OPVXX1(31, 268, 0) /* lxvx - ISA v3.0 */

		/* no AMOVWU */
	case AMOVB, AMOVBZ:
		return OPVCC(34, 0, 0, 0)
		/* load */

	case AMOVBU, AMOVBZU:
		return OPVCC(35, 0, 0, 0)
	case AFMOVD:
		return OPVCC(50, 0, 0, 0)
	case AFMOVDU:
		return OPVCC(51, 0, 0, 0)
	case AFMOVS:
		return OPVCC(48, 0, 0, 0)
	case AFMOVSU:
		return OPVCC(49, 0, 0, 0)
	case AMOVH:
		return OPVCC(42, 0, 0, 0)
	case AMOVHU:
		return OPVCC(43, 0, 0, 0)
	case AMOVHZ:
		return OPVCC(40, 0, 0, 0)
	case AMOVHZU:
		return OPVCC(41, 0, 0, 0)
	case AMOVMW:
		return OPVCC(46, 0, 0, 0) /* lmw */
	}

	c.ctxt.Diag("bad load opcode %v", a)
	return 0
}

/*
 * indexed load a(b),d
 */
func (c *ctxt9) oploadx(a obj.As) uint32 {
	switch a {
	case AMOVWZ:
		return OPVCC(31, 23, 0, 0) /* lwzx */
	case AMOVWZU:
		return OPVCC(31, 55, 0, 0) /* lwzux */
	case AMOVW:
		return OPVCC(31, 341, 0, 0) /* lwax */
	case AMOVWU:
		return OPVCC(31, 373, 0, 0) /* lwaux */

	case AMOVB, AMOVBZ:
		return OPVCC(31, 87, 0, 0) /* lbzx */

	case AMOVBU, AMOVBZU:
		return OPVCC(31, 119, 0, 0) /* lbzux */
	case AFMOVD:
		return OPVCC(31, 599, 0, 0) /* lfdx */
	case AFMOVDU:
		return OPVCC(31, 631, 0, 0) /*  lfdux */
	case AFMOVS:
		return OPVCC(31, 535, 0, 0) /* lfsx */
	case AFMOVSU:
		return OPVCC(31, 567, 0, 0) /* lfsux */
	case AFMOVSX:
		return OPVCC(31, 855, 0, 0) /* lfiwax - power6, isa 2.05 */
	case AFMOVSZ:
		return OPVCC(31, 887, 0, 0) /* lfiwzx - power7, isa 2.06 */
	case AMOVH:
		return OPVCC(31, 343, 0, 0) /* lhax */
	case AMOVHU:
		return OPVCC(31, 375, 0, 0) /* lhaux */
	case AMOVHBR:
		return OPVCC(31, 790, 0, 0) /* lhbrx */
	case AMOVWBR:
		return OPVCC(31, 534, 0, 0) /* lwbrx */
	case AMOVDBR:
		return OPVCC(31, 532, 0, 0) /* ldbrx */
	case AMOVHZ:
		return OPVCC(31, 279, 0, 0) /* lhzx */
	case AMOVHZU:
		return OPVCC(31, 311, 0, 0) /* lhzux */
	case ALBAR:
		return OPVCC(31, 52, 0, 0) /* lbarx */
	case ALHAR:
		return OPVCC(31, 116, 0, 0) /* lharx */
	case ALWAR:
		return OPVCC(31, 20, 0, 0) /* lwarx */
	case ALDAR:
		return OPVCC(31, 84, 0, 0) /* ldarx */
	case ALSW:
		return OPVCC(31, 533, 0, 0) /* lswx */
	case AMOVD:
		return OPVCC(31, 21, 0, 0) /* ldx */
	case AMOVDU:
		return OPVCC(31, 53, 0, 0) /* ldux */

	/* Vector (VMX/Altivec) instructions */
	case ALVEBX:
		return OPVCC(31, 7, 0, 0) /* lvebx - v2.03 */
	case ALVEHX:
		return OPVCC(31, 39, 0, 0) /* lvehx - v2.03 */
	case ALVEWX:
		return OPVCC(31, 71, 0, 0) /* lvewx - v2.03 */
	case ALVX:
		return OPVCC(31, 103, 0, 0) /* lvx - v2.03 */
	case ALVXL:
		return OPVCC(31, 359, 0, 0) /* lvxl - v2.03 */
	case ALVSL:
		return OPVCC(31, 6, 0, 0) /* lvsl - v2.03 */
	case ALVSR:
		return OPVCC(31, 38, 0, 0) /* lvsr - v2.03 */
		/* End of vector instructions */

	/* Vector scalar (VSX) instructions */
	case ALXVX:
		return OPVXX1(31, 268, 0) /* lxvx - ISA v3.0 */
	case ALXVD2X:
		return OPVXX1(31, 844, 0) /* lxvd2x - v2.06 */
	case ALXVW4X:
		return OPVXX1(31, 780, 0) /* lxvw4x - v2.06 */
	case ALXVH8X:
		return OPVXX1(31, 812, 0) /* lxvh8x - v3.00 */
	case ALXVB16X:
		return OPVXX1(31, 876, 0) /* lxvb16x - v3.00 */
	case ALXVDSX:
		return OPVXX1(31, 332, 0) /* lxvdsx - v2.06 */
	case ALXSDX:
		return OPVXX1(31, 588, 0) /* lxsdx - v2.06 */
	case ALXSIWAX:
		return OPVXX1(31, 76, 0) /* lxsiwax - v2.07 */
	case ALXSIWZX:
		return OPVXX1(31, 12, 0) /* lxsiwzx - v2.07 */
	}

	c.ctxt.Diag("bad loadx opcode %v", a)
	return 0
}

/*
 * store s,o(d)
 */
func (c *ctxt9) opstore(a obj.As) uint32 {
	switch a {
	case AMOVB, AMOVBZ:
		return OPVCC(38, 0, 0, 0) /* stb */

	case AMOVBU, AMOVBZU:
		return OPVCC(39, 0, 0, 0) /* stbu */
	case AFMOVD:
		return OPVCC(54, 0, 0, 0) /* stfd */
	case AFMOVDU:
		return OPVCC(55, 0, 0, 0) /* stfdu */
	case AFMOVS:
		return OPVCC(52, 0, 0, 0) /* stfs */
	case AFMOVSU:
		return OPVCC(53, 0, 0, 0) /* stfsu */

	case AMOVHZ, AMOVH:
		return OPVCC(44, 0, 0, 0) /* sth */

	case AMOVHZU, AMOVHU:
		return OPVCC(45, 0, 0, 0) /* sthu */
	case AMOVMW:
		return OPVCC(47, 0, 0, 0) /* stmw */
	case ASTSW:
		return OPVCC(31, 725, 0, 0) /* stswi */

	case AMOVWZ, AMOVW:
		return OPVCC(36, 0, 0, 0) /* stw */

	case AMOVWZU, AMOVWU:
		return OPVCC(37, 0, 0, 0) /* stwu */
	case AMOVD:
		return OPVCC(62, 0, 0, 0) /* std */
	case AMOVDU:
		return OPVCC(62, 0, 0, 1) /* stdu */
	case ASTXV:
		return OPDQ(61, 5, 0) /* stxv ISA 3.0 */
	case ASTXVL:
		return OPVXX1(31, 397, 0) /* stxvl ISA 3.0 */
	case ASTXVLL:
		return OPVXX1(31, 429, 0) /* stxvll ISA 3.0 */
	case ASTXVX:
		return OPVXX1(31, 396, 0) /* stxvx - ISA v3.0 */

	}

	c.ctxt.Diag("unknown store opcode %v", a)
	return 0
}

/*
 * indexed store s,a(b)
 */
func (c *ctxt9) opstorex(a obj.As) uint32 {
	switch a {
	case AMOVB, AMOVBZ:
		return OPVCC(31, 215, 0, 0) /* stbx */

	case AMOVBU, AMOVBZU:
		return OPVCC(31, 247, 0, 0) /* stbux */
	case AFMOVD:
		return OPVCC(31, 727, 0, 0) /* stfdx */
	case AFMOVDU:
		return OPVCC(31, 759, 0, 0) /* stfdux */
	case AFMOVS:
		return OPVCC(31, 663, 0, 0) /* stfsx */
	case AFMOVSU:
		return OPVCC(31, 695, 0, 0) /* stfsux */
	case AFMOVSX:
		return OPVCC(31, 983, 0, 0) /* stfiwx */

	case AMOVHZ, AMOVH:
		return OPVCC(31, 407, 0, 0) /* sthx */
	case AMOVHBR:
		return OPVCC(31, 918, 0, 0) /* sthbrx */

	case AMOVHZU, AMOVHU:
		return OPVCC(31, 439, 0, 0) /* sthux */

	case AMOVWZ, AMOVW:
		return OPVCC(31, 151, 0, 0) /* stwx */

	case AMOVWZU, AMOVWU:
		return OPVCC(31, 183, 0, 0) /* stwux */
	case ASTSW:
		return OPVCC(31, 661, 0, 0) /* stswx */
	case AMOVWBR:
		return OPVCC(31, 662, 0, 0) /* stwbrx */
	case AMOVDBR:
		return OPVCC(31, 660, 0, 0) /* stdbrx */
	case ASTBCCC:
		return OPVCC(31, 694, 0, 1) /* stbcx. */
	case ASTHCCC:
		return OPVCC(31, 726, 0, 1) /* sthcx. */
	case ASTWCCC:
		return OPVCC(31, 150, 0, 1) /* stwcx. */
	case ASTDCCC:
		return OPVCC(31, 214, 0, 1) /* stwdx. */
	case AMOVD:
		return OPVCC(31, 149, 0, 0) /* stdx */
	case AMOVDU:
		return OPVCC(31, 181, 0, 0) /* stdux */

	/* Vector (VMX/Altivec) instructions */
	case ASTVEBX:
		return OPVCC(31, 135, 0, 0) /* stvebx - v2.03 */
	case ASTVEHX:
		return OPVCC(31, 167, 0, 0) /* stvehx - v2.03 */
	case ASTVEWX:
		return OPVCC(31, 199, 0, 0) /* stvewx - v2.03 */
	case ASTVX:
		return OPVCC(31, 231, 0, 0) /* stvx - v2.03 */
	case ASTVXL:
		return OPVCC(31, 487, 0, 0) /* stvxl - v2.03 */
		/* End of vector instructions */

	/* Vector scalar (VSX) instructions */
	case ASTXVX:
		return OPVXX1(31, 396, 0) /* stxvx - v3.0 */
	case ASTXVD2X:
		return OPVXX1(31, 972, 0) /* stxvd2x - v2.06 */
	case ASTXVW4X:
		return OPVXX1(31, 908, 0) /* stxvw4x - v2.06 */
	case ASTXVH8X:
		return OPVXX1(31, 940, 0) /* stxvh8x - v3.0 */
	case ASTXVB16X:
		return OPVXX1(31, 1004, 0) /* stxvb16x - v3.0 */

	case ASTXSDX:
		return OPVXX1(31, 716, 0) /* stxsdx - v2.06 */

	case ASTXSIWX:
		return OPVXX1(31, 140, 0) /* stxsiwx - v2.07 */

		/* End of vector scalar instructions */

	}

	c.ctxt.Diag("unknown storex opcode %v", a)
	return 0
}
