]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/mips: copy cmd/internal/obj/ppc64
authorShenghou Ma <minux@golang.org>
Sun, 6 Sep 2015 00:27:00 +0000 (20:27 -0400)
committerMinux Ma <minux@golang.org>
Tue, 8 Sep 2015 22:39:56 +0000 (22:39 +0000)
Just a mechanical copy with filename renames, no code changes.
This is to reduce code difference when adding the mips64 port.

Change-Id: Id06e975f414a7b09f4827167b30813b228a3bfae
Reviewed-on: https://go-review.googlesource.com/14323
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/internal/obj/mips/a.out.go [new file with mode: 0644]
src/cmd/internal/obj/mips/anames.go [new file with mode: 0644]
src/cmd/internal/obj/mips/anames0.go [new file with mode: 0644]
src/cmd/internal/obj/mips/asm0.go [new file with mode: 0644]
src/cmd/internal/obj/mips/list0.go [new file with mode: 0644]
src/cmd/internal/obj/mips/obj0.go [new file with mode: 0644]

diff --git a/src/cmd/internal/obj/mips/a.out.go b/src/cmd/internal/obj/mips/a.out.go
new file mode 100644 (file)
index 0000000..3028b6c
--- /dev/null
@@ -0,0 +1,538 @@
+// cmd/9c/9.out.h 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"
+
+//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p ppc64
+
+/*
+ * powerpc 64
+ */
+const (
+       NSNAME = 8
+       NSYM   = 50
+       NREG   = 32 /* number of general registers */
+       NFREG  = 32 /* number of floating point registers */
+)
+
+const (
+       REG_R0 = obj.RBasePPC64 + iota
+       REG_R1
+       REG_R2
+       REG_R3
+       REG_R4
+       REG_R5
+       REG_R6
+       REG_R7
+       REG_R8
+       REG_R9
+       REG_R10
+       REG_R11
+       REG_R12
+       REG_R13
+       REG_R14
+       REG_R15
+       REG_R16
+       REG_R17
+       REG_R18
+       REG_R19
+       REG_R20
+       REG_R21
+       REG_R22
+       REG_R23
+       REG_R24
+       REG_R25
+       REG_R26
+       REG_R27
+       REG_R28
+       REG_R29
+       REG_R30
+       REG_R31
+
+       REG_F0
+       REG_F1
+       REG_F2
+       REG_F3
+       REG_F4
+       REG_F5
+       REG_F6
+       REG_F7
+       REG_F8
+       REG_F9
+       REG_F10
+       REG_F11
+       REG_F12
+       REG_F13
+       REG_F14
+       REG_F15
+       REG_F16
+       REG_F17
+       REG_F18
+       REG_F19
+       REG_F20
+       REG_F21
+       REG_F22
+       REG_F23
+       REG_F24
+       REG_F25
+       REG_F26
+       REG_F27
+       REG_F28
+       REG_F29
+       REG_F30
+       REG_F31
+
+       REG_CR0
+       REG_CR1
+       REG_CR2
+       REG_CR3
+       REG_CR4
+       REG_CR5
+       REG_CR6
+       REG_CR7
+
+       REG_MSR
+       REG_FPSCR
+       REG_CR
+
+       REG_SPECIAL = REG_CR0
+
+       REG_SPR0 = obj.RBasePPC64 + 1024 // first of 1024 registers
+       REG_DCR0 = obj.RBasePPC64 + 2048 // first of 1024 registers
+
+       REG_XER = REG_SPR0 + 1
+       REG_LR  = REG_SPR0 + 8
+       REG_CTR = REG_SPR0 + 9
+
+       REGZERO  = REG_R0 /* set to zero */
+       REGSP    = REG_R1
+       REGSB    = REG_R2
+       REGRET   = REG_R3
+       REGARG   = -1      /* -1 disables passing the first argument in register */
+       REGRT1   = REG_R3  /* reserved for runtime, duffzero and duffcopy */
+       REGRT2   = REG_R4  /* reserved for runtime, duffcopy */
+       REGMIN   = REG_R7  /* register variables allocated from here to REGMAX */
+       REGCTXT  = REG_R11 /* context for closures */
+       REGTLS   = REG_R13 /* C ABI TLS base pointer */
+       REGMAX   = REG_R27
+       REGEXT   = REG_R30 /* external registers allocated from here down */
+       REGG     = REG_R30 /* G */
+       REGTMP   = REG_R31 /* used by the linker */
+       FREGRET  = REG_F0
+       FREGMIN  = REG_F17 /* first register variable */
+       FREGMAX  = REG_F26 /* last register variable for 9g only */
+       FREGEXT  = REG_F26 /* first external register */
+       FREGCVI  = REG_F27 /* floating conversion constant */
+       FREGZERO = REG_F28 /* both float and double */
+       FREGHALF = REG_F29 /* double */
+       FREGONE  = REG_F30 /* double */
+       FREGTWO  = REG_F31 /* double */
+)
+
+/*
+ * GENERAL:
+ *
+ * compiler allocates R3 up as temps
+ * compiler allocates register variables R7-R27
+ * compiler allocates external registers R30 down
+ *
+ * compiler allocates register variables F17-F26
+ * compiler allocates external registers F26 down
+ */
+const (
+       BIG = 32768 - 8
+)
+
+const (
+       /* mark flags */
+       LABEL   = 1 << 0
+       LEAF    = 1 << 1
+       FLOAT   = 1 << 2
+       BRANCH  = 1 << 3
+       LOAD    = 1 << 4
+       FCMP    = 1 << 5
+       SYNC    = 1 << 6
+       LIST    = 1 << 7
+       FOLL    = 1 << 8
+       NOSCHED = 1 << 9
+)
+
+const (
+       C_NONE = iota
+       C_REG
+       C_FREG
+       C_CREG
+       C_SPR /* special processor register */
+       C_ZCON
+       C_SCON   /* 16 bit signed */
+       C_UCON   /* 32 bit signed, low 16 bits 0 */
+       C_ADDCON /* -0x8000 <= v < 0 */
+       C_ANDCON /* 0 < v <= 0xFFFF */
+       C_LCON   /* other 32 */
+       C_DCON   /* other 64 (could subdivide further) */
+       C_SACON  /* $n(REG) where n <= int16 */
+       C_SECON
+       C_LACON /* $n(REG) where int16 < n <= int32 */
+       C_LECON
+       C_DACON /* $n(REG) where int32 < n */
+       C_SBRA
+       C_LBRA
+       C_SAUTO
+       C_LAUTO
+       C_SEXT
+       C_LEXT
+       C_ZOREG
+       C_SOREG
+       C_LOREG
+       C_FPSCR
+       C_MSR
+       C_XER
+       C_LR
+       C_CTR
+       C_ANY
+       C_GOK
+       C_ADDR
+       C_TEXTSIZE
+
+       C_NCLASS /* must be the last */
+)
+
+const (
+       AADD = obj.ABasePPC64 + obj.A_ARCHSPECIFIC + iota
+       AADDCC
+       AADDV
+       AADDVCC
+       AADDC
+       AADDCCC
+       AADDCV
+       AADDCVCC
+       AADDME
+       AADDMECC
+       AADDMEVCC
+       AADDMEV
+       AADDE
+       AADDECC
+       AADDEVCC
+       AADDEV
+       AADDZE
+       AADDZECC
+       AADDZEVCC
+       AADDZEV
+       AAND
+       AANDCC
+       AANDN
+       AANDNCC
+       ABC
+       ABCL
+       ABEQ
+       ABGE
+       ABGT
+       ABLE
+       ABLT
+       ABNE
+       ABVC
+       ABVS
+       ACMP
+       ACMPU
+       ACNTLZW
+       ACNTLZWCC
+       ACRAND
+       ACRANDN
+       ACREQV
+       ACRNAND
+       ACRNOR
+       ACROR
+       ACRORN
+       ACRXOR
+       ADIVW
+       ADIVWCC
+       ADIVWVCC
+       ADIVWV
+       ADIVWU
+       ADIVWUCC
+       ADIVWUVCC
+       ADIVWUV
+       AEQV
+       AEQVCC
+       AEXTSB
+       AEXTSBCC
+       AEXTSH
+       AEXTSHCC
+       AFABS
+       AFABSCC
+       AFADD
+       AFADDCC
+       AFADDS
+       AFADDSCC
+       AFCMPO
+       AFCMPU
+       AFCTIW
+       AFCTIWCC
+       AFCTIWZ
+       AFCTIWZCC
+       AFDIV
+       AFDIVCC
+       AFDIVS
+       AFDIVSCC
+       AFMADD
+       AFMADDCC
+       AFMADDS
+       AFMADDSCC
+       AFMOVD
+       AFMOVDCC
+       AFMOVDU
+       AFMOVS
+       AFMOVSU
+       AFMSUB
+       AFMSUBCC
+       AFMSUBS
+       AFMSUBSCC
+       AFMUL
+       AFMULCC
+       AFMULS
+       AFMULSCC
+       AFNABS
+       AFNABSCC
+       AFNEG
+       AFNEGCC
+       AFNMADD
+       AFNMADDCC
+       AFNMADDS
+       AFNMADDSCC
+       AFNMSUB
+       AFNMSUBCC
+       AFNMSUBS
+       AFNMSUBSCC
+       AFRSP
+       AFRSPCC
+       AFSUB
+       AFSUBCC
+       AFSUBS
+       AFSUBSCC
+       AMOVMW
+       ALSW
+       ALWAR
+       AMOVWBR
+       AMOVB
+       AMOVBU
+       AMOVBZ
+       AMOVBZU
+       AMOVH
+       AMOVHBR
+       AMOVHU
+       AMOVHZ
+       AMOVHZU
+       AMOVW
+       AMOVWU
+       AMOVFL
+       AMOVCRFS
+       AMTFSB0
+       AMTFSB0CC
+       AMTFSB1
+       AMTFSB1CC
+       AMULHW
+       AMULHWCC
+       AMULHWU
+       AMULHWUCC
+       AMULLW
+       AMULLWCC
+       AMULLWVCC
+       AMULLWV
+       ANAND
+       ANANDCC
+       ANEG
+       ANEGCC
+       ANEGVCC
+       ANEGV
+       ANOR
+       ANORCC
+       AOR
+       AORCC
+       AORN
+       AORNCC
+       AREM
+       AREMCC
+       AREMV
+       AREMVCC
+       AREMU
+       AREMUCC
+       AREMUV
+       AREMUVCC
+       ARFI
+       ARLWMI
+       ARLWMICC
+       ARLWNM
+       ARLWNMCC
+       ASLW
+       ASLWCC
+       ASRW
+       ASRAW
+       ASRAWCC
+       ASRWCC
+       ASTSW
+       ASTWCCC
+       ASUB
+       ASUBCC
+       ASUBVCC
+       ASUBC
+       ASUBCCC
+       ASUBCV
+       ASUBCVCC
+       ASUBME
+       ASUBMECC
+       ASUBMEVCC
+       ASUBMEV
+       ASUBV
+       ASUBE
+       ASUBECC
+       ASUBEV
+       ASUBEVCC
+       ASUBZE
+       ASUBZECC
+       ASUBZEVCC
+       ASUBZEV
+       ASYNC
+       AXOR
+       AXORCC
+
+       ADCBF
+       ADCBI
+       ADCBST
+       ADCBT
+       ADCBTST
+       ADCBZ
+       AECIWX
+       AECOWX
+       AEIEIO
+       AICBI
+       AISYNC
+       APTESYNC
+       ATLBIE
+       ATLBIEL
+       ATLBSYNC
+       ATW
+
+       ASYSCALL
+       AWORD
+
+       ARFCI
+
+       /* optional on 32-bit */
+       AFRES
+       AFRESCC
+       AFRSQRTE
+       AFRSQRTECC
+       AFSEL
+       AFSELCC
+       AFSQRT
+       AFSQRTCC
+       AFSQRTS
+       AFSQRTSCC
+
+       /* 64-bit */
+
+       ACNTLZD
+       ACNTLZDCC
+       ACMPW /* CMP with L=0 */
+       ACMPWU
+       ADIVD
+       ADIVDCC
+       ADIVDVCC
+       ADIVDV
+       ADIVDU
+       ADIVDUCC
+       ADIVDUVCC
+       ADIVDUV
+       AEXTSW
+       AEXTSWCC
+       /* AFCFIW; AFCFIWCC */
+       AFCFID
+       AFCFIDCC
+       AFCTID
+       AFCTIDCC
+       AFCTIDZ
+       AFCTIDZCC
+       ALDAR
+       AMOVD
+       AMOVDU
+       AMOVWZ
+       AMOVWZU
+       AMULHD
+       AMULHDCC
+       AMULHDU
+       AMULHDUCC
+       AMULLD
+       AMULLDCC
+       AMULLDVCC
+       AMULLDV
+       ARFID
+       ARLDMI
+       ARLDMICC
+       ARLDC
+       ARLDCCC
+       ARLDCR
+       ARLDCRCC
+       ARLDCL
+       ARLDCLCC
+       ASLBIA
+       ASLBIE
+       ASLBMFEE
+       ASLBMFEV
+       ASLBMTE
+       ASLD
+       ASLDCC
+       ASRD
+       ASRAD
+       ASRADCC
+       ASRDCC
+       ASTDCCC
+       ATD
+
+       /* 64-bit pseudo operation */
+       ADWORD
+       AREMD
+       AREMDCC
+       AREMDV
+       AREMDVCC
+       AREMDU
+       AREMDUCC
+       AREMDUV
+       AREMDUVCC
+
+       /* more 64-bit operations */
+       AHRFID
+
+       ALAST
+
+       // aliases
+       ABR = obj.AJMP
+       ABL = obj.ACALL
+)
diff --git a/src/cmd/internal/obj/mips/anames.go b/src/cmd/internal/obj/mips/anames.go
new file mode 100644 (file)
index 0000000..1ae7a52
--- /dev/null
@@ -0,0 +1,300 @@
+// Generated by stringer -i a.out.go -o anames.go -p ppc64
+// Do not edit.
+
+package ppc64
+
+import "cmd/internal/obj"
+
+var Anames = []string{
+       obj.A_ARCHSPECIFIC: "ADD",
+       "ADDCC",
+       "ADDV",
+       "ADDVCC",
+       "ADDC",
+       "ADDCCC",
+       "ADDCV",
+       "ADDCVCC",
+       "ADDME",
+       "ADDMECC",
+       "ADDMEVCC",
+       "ADDMEV",
+       "ADDE",
+       "ADDECC",
+       "ADDEVCC",
+       "ADDEV",
+       "ADDZE",
+       "ADDZECC",
+       "ADDZEVCC",
+       "ADDZEV",
+       "AND",
+       "ANDCC",
+       "ANDN",
+       "ANDNCC",
+       "BC",
+       "BCL",
+       "BEQ",
+       "BGE",
+       "BGT",
+       "BLE",
+       "BLT",
+       "BNE",
+       "BVC",
+       "BVS",
+       "CMP",
+       "CMPU",
+       "CNTLZW",
+       "CNTLZWCC",
+       "CRAND",
+       "CRANDN",
+       "CREQV",
+       "CRNAND",
+       "CRNOR",
+       "CROR",
+       "CRORN",
+       "CRXOR",
+       "DIVW",
+       "DIVWCC",
+       "DIVWVCC",
+       "DIVWV",
+       "DIVWU",
+       "DIVWUCC",
+       "DIVWUVCC",
+       "DIVWUV",
+       "EQV",
+       "EQVCC",
+       "EXTSB",
+       "EXTSBCC",
+       "EXTSH",
+       "EXTSHCC",
+       "FABS",
+       "FABSCC",
+       "FADD",
+       "FADDCC",
+       "FADDS",
+       "FADDSCC",
+       "FCMPO",
+       "FCMPU",
+       "FCTIW",
+       "FCTIWCC",
+       "FCTIWZ",
+       "FCTIWZCC",
+       "FDIV",
+       "FDIVCC",
+       "FDIVS",
+       "FDIVSCC",
+       "FMADD",
+       "FMADDCC",
+       "FMADDS",
+       "FMADDSCC",
+       "FMOVD",
+       "FMOVDCC",
+       "FMOVDU",
+       "FMOVS",
+       "FMOVSU",
+       "FMSUB",
+       "FMSUBCC",
+       "FMSUBS",
+       "FMSUBSCC",
+       "FMUL",
+       "FMULCC",
+       "FMULS",
+       "FMULSCC",
+       "FNABS",
+       "FNABSCC",
+       "FNEG",
+       "FNEGCC",
+       "FNMADD",
+       "FNMADDCC",
+       "FNMADDS",
+       "FNMADDSCC",
+       "FNMSUB",
+       "FNMSUBCC",
+       "FNMSUBS",
+       "FNMSUBSCC",
+       "FRSP",
+       "FRSPCC",
+       "FSUB",
+       "FSUBCC",
+       "FSUBS",
+       "FSUBSCC",
+       "MOVMW",
+       "LSW",
+       "LWAR",
+       "MOVWBR",
+       "MOVB",
+       "MOVBU",
+       "MOVBZ",
+       "MOVBZU",
+       "MOVH",
+       "MOVHBR",
+       "MOVHU",
+       "MOVHZ",
+       "MOVHZU",
+       "MOVW",
+       "MOVWU",
+       "MOVFL",
+       "MOVCRFS",
+       "MTFSB0",
+       "MTFSB0CC",
+       "MTFSB1",
+       "MTFSB1CC",
+       "MULHW",
+       "MULHWCC",
+       "MULHWU",
+       "MULHWUCC",
+       "MULLW",
+       "MULLWCC",
+       "MULLWVCC",
+       "MULLWV",
+       "NAND",
+       "NANDCC",
+       "NEG",
+       "NEGCC",
+       "NEGVCC",
+       "NEGV",
+       "NOR",
+       "NORCC",
+       "OR",
+       "ORCC",
+       "ORN",
+       "ORNCC",
+       "REM",
+       "REMCC",
+       "REMV",
+       "REMVCC",
+       "REMU",
+       "REMUCC",
+       "REMUV",
+       "REMUVCC",
+       "RFI",
+       "RLWMI",
+       "RLWMICC",
+       "RLWNM",
+       "RLWNMCC",
+       "SLW",
+       "SLWCC",
+       "SRW",
+       "SRAW",
+       "SRAWCC",
+       "SRWCC",
+       "STSW",
+       "STWCCC",
+       "SUB",
+       "SUBCC",
+       "SUBVCC",
+       "SUBC",
+       "SUBCCC",
+       "SUBCV",
+       "SUBCVCC",
+       "SUBME",
+       "SUBMECC",
+       "SUBMEVCC",
+       "SUBMEV",
+       "SUBV",
+       "SUBE",
+       "SUBECC",
+       "SUBEV",
+       "SUBEVCC",
+       "SUBZE",
+       "SUBZECC",
+       "SUBZEVCC",
+       "SUBZEV",
+       "SYNC",
+       "XOR",
+       "XORCC",
+       "DCBF",
+       "DCBI",
+       "DCBST",
+       "DCBT",
+       "DCBTST",
+       "DCBZ",
+       "ECIWX",
+       "ECOWX",
+       "EIEIO",
+       "ICBI",
+       "ISYNC",
+       "PTESYNC",
+       "TLBIE",
+       "TLBIEL",
+       "TLBSYNC",
+       "TW",
+       "SYSCALL",
+       "WORD",
+       "RFCI",
+       "FRES",
+       "FRESCC",
+       "FRSQRTE",
+       "FRSQRTECC",
+       "FSEL",
+       "FSELCC",
+       "FSQRT",
+       "FSQRTCC",
+       "FSQRTS",
+       "FSQRTSCC",
+       "CNTLZD",
+       "CNTLZDCC",
+       "CMPW",
+       "CMPWU",
+       "DIVD",
+       "DIVDCC",
+       "DIVDVCC",
+       "DIVDV",
+       "DIVDU",
+       "DIVDUCC",
+       "DIVDUVCC",
+       "DIVDUV",
+       "EXTSW",
+       "EXTSWCC",
+       "FCFID",
+       "FCFIDCC",
+       "FCTID",
+       "FCTIDCC",
+       "FCTIDZ",
+       "FCTIDZCC",
+       "LDAR",
+       "MOVD",
+       "MOVDU",
+       "MOVWZ",
+       "MOVWZU",
+       "MULHD",
+       "MULHDCC",
+       "MULHDU",
+       "MULHDUCC",
+       "MULLD",
+       "MULLDCC",
+       "MULLDVCC",
+       "MULLDV",
+       "RFID",
+       "RLDMI",
+       "RLDMICC",
+       "RLDC",
+       "RLDCCC",
+       "RLDCR",
+       "RLDCRCC",
+       "RLDCL",
+       "RLDCLCC",
+       "SLBIA",
+       "SLBIE",
+       "SLBMFEE",
+       "SLBMFEV",
+       "SLBMTE",
+       "SLD",
+       "SLDCC",
+       "SRD",
+       "SRAD",
+       "SRADCC",
+       "SRDCC",
+       "STDCCC",
+       "TD",
+       "DWORD",
+       "REMD",
+       "REMDCC",
+       "REMDV",
+       "REMDVCC",
+       "REMDU",
+       "REMDUCC",
+       "REMDUV",
+       "REMDUVCC",
+       "HRFID",
+       "LAST",
+}
diff --git a/src/cmd/internal/obj/mips/anames0.go b/src/cmd/internal/obj/mips/anames0.go
new file mode 100644 (file)
index 0000000..b48e516
--- /dev/null
@@ -0,0 +1,40 @@
+package ppc64
+
+var cnames9 = []string{
+       "NONE",
+       "REG",
+       "FREG",
+       "CREG",
+       "SPR",
+       "ZCON",
+       "SCON",
+       "UCON",
+       "ADDCON",
+       "ANDCON",
+       "LCON",
+       "DCON",
+       "SACON",
+       "SECON",
+       "LACON",
+       "LECON",
+       "DACON",
+       "SBRA",
+       "LBRA",
+       "SAUTO",
+       "LAUTO",
+       "SEXT",
+       "LEXT",
+       "ZOREG",
+       "SOREG",
+       "LOREG",
+       "FPSCR",
+       "MSR",
+       "XER",
+       "LR",
+       "CTR",
+       "ANY",
+       "GOK",
+       "ADDR",
+       "TEXTSIZE",
+       "NCLASS",
+}
diff --git a/src/cmd/internal/obj/mips/asm0.go b/src/cmd/internal/obj/mips/asm0.go
new file mode 100644 (file)
index 0000000..2955a00
--- /dev/null
@@ -0,0 +1,3247 @@
+// 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"
+       "encoding/binary"
+       "fmt"
+       "log"
+       "sort"
+)
+
+// Instruction layout.
+
+const (
+       FuncAlign = 8
+)
+
+const (
+       r0iszero = 1
+)
+
+type Optab struct {
+       as    int16
+       a1    uint8
+       a2    uint8
+       a3    uint8
+       a4    uint8
+       type_ int8
+       size  int8
+       param int16
+}
+
+var optab = []Optab{
+       Optab{obj.ATEXT, C_LEXT, C_NONE, C_NONE, C_TEXTSIZE, 0, 0, 0},
+       Optab{obj.ATEXT, C_LEXT, C_NONE, C_LCON, C_TEXTSIZE, 0, 0, 0},
+       Optab{obj.ATEXT, C_ADDR, C_NONE, C_NONE, C_TEXTSIZE, 0, 0, 0},
+       Optab{obj.ATEXT, C_ADDR, C_NONE, C_LCON, C_TEXTSIZE, 0, 0, 0},
+       /* move register */
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0},
+       Optab{AMOVB, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0},
+       Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0},
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0},
+       Optab{AADD, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0},
+       Optab{AADD, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0},
+       Optab{AADD, C_ADDCON, C_REG, C_NONE, C_REG, 4, 4, 0},
+       Optab{AADD, C_ADDCON, C_NONE, C_NONE, C_REG, 4, 4, 0},
+       Optab{AADD, C_UCON, C_REG, C_NONE, C_REG, 20, 4, 0},
+       Optab{AADD, C_UCON, C_NONE, C_NONE, C_REG, 20, 4, 0},
+       Optab{AADD, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0},
+       Optab{AADD, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0},
+       Optab{AADDC, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0},
+       Optab{AADDC, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0},
+       Optab{AADDC, C_ADDCON, C_REG, C_NONE, C_REG, 4, 4, 0},
+       Optab{AADDC, C_ADDCON, C_NONE, C_NONE, C_REG, 4, 4, 0},
+       Optab{AADDC, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0},
+       Optab{AADDC, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0},
+       Optab{AAND, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0}, /* logical, no literal */
+       Optab{AAND, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+       Optab{AANDCC, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0},
+       Optab{AANDCC, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+       Optab{AANDCC, C_ANDCON, C_NONE, C_NONE, C_REG, 58, 4, 0},
+       Optab{AANDCC, C_ANDCON, C_REG, C_NONE, C_REG, 58, 4, 0},
+       Optab{AANDCC, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0},
+       Optab{AANDCC, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0},
+       Optab{AANDCC, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0},
+       Optab{AANDCC, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0},
+       Optab{AMULLW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0},
+       Optab{AMULLW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0},
+       Optab{AMULLW, C_ADDCON, C_REG, C_NONE, C_REG, 4, 4, 0},
+       Optab{AMULLW, C_ADDCON, C_NONE, C_NONE, C_REG, 4, 4, 0},
+       Optab{AMULLW, C_ANDCON, C_REG, C_NONE, C_REG, 4, 4, 0},
+       Optab{AMULLW, C_ANDCON, C_NONE, C_NONE, C_REG, 4, 4, 0},
+       Optab{AMULLW, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0},
+       Optab{AMULLW, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0},
+       Optab{ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0},
+       Optab{ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0},
+       Optab{ASUBC, C_REG, C_NONE, C_ADDCON, C_REG, 27, 4, 0},
+       Optab{ASUBC, C_REG, C_NONE, C_LCON, C_REG, 28, 12, 0},
+       Optab{AOR, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0}, /* logical, literal not cc (or/xor) */
+       Optab{AOR, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+       Optab{AOR, C_ANDCON, C_NONE, C_NONE, C_REG, 58, 4, 0},
+       Optab{AOR, C_ANDCON, C_REG, C_NONE, C_REG, 58, 4, 0},
+       Optab{AOR, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0},
+       Optab{AOR, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0},
+       Optab{AOR, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0},
+       Optab{AOR, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0},
+       Optab{ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0}, /* op r1[,r2],r3 */
+       Optab{ADIVW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0},
+       Optab{ASUB, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0}, /* op r2[,r1],r3 */
+       Optab{ASUB, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0},
+       Optab{ASLW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+       Optab{ASLW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0},
+       Optab{ASLD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+       Optab{ASLD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0},
+       Optab{ASLD, C_SCON, C_REG, C_NONE, C_REG, 25, 4, 0},
+       Optab{ASLD, C_SCON, C_NONE, C_NONE, C_REG, 25, 4, 0},
+       Optab{ASLW, C_SCON, C_REG, C_NONE, C_REG, 57, 4, 0},
+       Optab{ASLW, C_SCON, C_NONE, C_NONE, C_REG, 57, 4, 0},
+       Optab{ASRAW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+       Optab{ASRAW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0},
+       Optab{ASRAW, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0},
+       Optab{ASRAW, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0},
+       Optab{ASRAD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+       Optab{ASRAD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0},
+       Optab{ASRAD, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0},
+       Optab{ASRAD, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0},
+       Optab{ARLWMI, C_SCON, C_REG, C_LCON, C_REG, 62, 4, 0},
+       Optab{ARLWMI, C_REG, C_REG, C_LCON, C_REG, 63, 4, 0},
+       Optab{ARLDMI, C_SCON, C_REG, C_LCON, C_REG, 30, 4, 0},
+       Optab{ARLDC, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0},
+       Optab{ARLDCL, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0},
+       Optab{ARLDCL, C_REG, C_REG, C_LCON, C_REG, 14, 4, 0},
+       Optab{ARLDCL, C_REG, C_NONE, C_LCON, C_REG, 14, 4, 0},
+       Optab{AFADD, C_FREG, C_NONE, C_NONE, C_FREG, 2, 4, 0},
+       Optab{AFADD, C_FREG, C_REG, C_NONE, C_FREG, 2, 4, 0},
+       Optab{AFABS, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0},
+       Optab{AFABS, C_NONE, C_NONE, C_NONE, C_FREG, 33, 4, 0},
+       Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0},
+       Optab{AFMADD, C_FREG, C_REG, C_FREG, C_FREG, 34, 4, 0},
+       Optab{AFMUL, C_FREG, C_NONE, C_NONE, C_FREG, 32, 4, 0},
+       Optab{AFMUL, C_FREG, C_REG, C_NONE, C_FREG, 32, 4, 0},
+
+       /* store, short offset */
+       Optab{AMOVD, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+       Optab{AMOVW, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+       Optab{AMOVWZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+       Optab{AMOVBZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+       Optab{AMOVBZU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+       Optab{AMOVB, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+       Optab{AMOVBU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+       Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+       Optab{AMOVB, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+       Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+       Optab{AMOVB, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+       Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+       Optab{AMOVBZU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+       Optab{AMOVB, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+       Optab{AMOVBU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+
+       /* load, short offset */
+       Optab{AMOVD, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO},
+       Optab{AMOVW, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO},
+       Optab{AMOVWZ, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO},
+       Optab{AMOVBZ, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO},
+       Optab{AMOVBZU, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO},
+       Optab{AMOVB, C_ZOREG, C_REG, C_NONE, C_REG, 9, 8, REGZERO},
+       Optab{AMOVBU, C_ZOREG, C_REG, C_NONE, C_REG, 9, 8, REGZERO},
+       Optab{AMOVD, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB},
+       Optab{AMOVW, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB},
+       Optab{AMOVWZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB},
+       Optab{AMOVBZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB},
+       Optab{AMOVB, C_SEXT, C_NONE, C_NONE, C_REG, 9, 8, REGSB},
+       Optab{AMOVD, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP},
+       Optab{AMOVW, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP},
+       Optab{AMOVWZ, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP},
+       Optab{AMOVBZ, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP},
+       Optab{AMOVB, C_SAUTO, C_NONE, C_NONE, C_REG, 9, 8, REGSP},
+       Optab{AMOVD, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO},
+       Optab{AMOVW, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO},
+       Optab{AMOVWZ, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO},
+       Optab{AMOVBZ, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO},
+       Optab{AMOVBZU, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO},
+       Optab{AMOVB, C_SOREG, C_NONE, C_NONE, C_REG, 9, 8, REGZERO},
+       Optab{AMOVBU, C_SOREG, C_NONE, C_NONE, C_REG, 9, 8, REGZERO},
+
+       /* store, long offset */
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+       Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+       Optab{AMOVB, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+       Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+       Optab{AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+       Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+       Optab{AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+       Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+       Optab{AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+
+       /* load, long offset */
+       Optab{AMOVD, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB},
+       Optab{AMOVW, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB},
+       Optab{AMOVWZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB},
+       Optab{AMOVBZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB},
+       Optab{AMOVB, C_LEXT, C_NONE, C_NONE, C_REG, 37, 12, REGSB},
+       Optab{AMOVD, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP},
+       Optab{AMOVW, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP},
+       Optab{AMOVWZ, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP},
+       Optab{AMOVBZ, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP},
+       Optab{AMOVB, C_LAUTO, C_NONE, C_NONE, C_REG, 37, 12, REGSP},
+       Optab{AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO},
+       Optab{AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO},
+       Optab{AMOVWZ, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO},
+       Optab{AMOVBZ, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO},
+       Optab{AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 37, 12, REGZERO},
+       Optab{AMOVD, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0},
+       Optab{AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0},
+       Optab{AMOVWZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0},
+       Optab{AMOVBZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0},
+       Optab{AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 76, 12, 0},
+
+       /* load constant */
+       Optab{AMOVD, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB},
+       Optab{AMOVD, C_SACON, C_NONE, C_NONE, C_REG, 3, 4, REGSP},
+       Optab{AMOVD, C_LECON, C_NONE, C_NONE, C_REG, 26, 8, REGSB},
+       Optab{AMOVD, C_LACON, C_NONE, C_NONE, C_REG, 26, 8, REGSP},
+       Optab{AMOVD, C_ADDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+       Optab{AMOVW, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB}, /* TO DO: check */
+       Optab{AMOVW, C_SACON, C_NONE, C_NONE, C_REG, 3, 4, REGSP},
+       Optab{AMOVW, C_LECON, C_NONE, C_NONE, C_REG, 26, 8, REGSB},
+       Optab{AMOVW, C_LACON, C_NONE, C_NONE, C_REG, 26, 8, REGSP},
+       Optab{AMOVW, C_ADDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+       Optab{AMOVWZ, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB}, /* TO DO: check */
+       Optab{AMOVWZ, C_SACON, C_NONE, C_NONE, C_REG, 3, 4, REGSP},
+       Optab{AMOVWZ, C_LECON, C_NONE, C_NONE, C_REG, 26, 8, REGSB},
+       Optab{AMOVWZ, C_LACON, C_NONE, C_NONE, C_REG, 26, 8, REGSP},
+       Optab{AMOVWZ, C_ADDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+
+       /* load unsigned/long constants (TO DO: check) */
+       Optab{AMOVD, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+       Optab{AMOVD, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0},
+       Optab{AMOVW, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+       Optab{AMOVW, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0},
+       Optab{AMOVWZ, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+       Optab{AMOVWZ, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0},
+       Optab{AMOVHBR, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0},
+       Optab{AMOVHBR, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0},
+       Optab{AMOVHBR, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0},
+       Optab{AMOVHBR, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0},
+       Optab{ASYSCALL, C_NONE, C_NONE, C_NONE, C_NONE, 5, 4, 0},
+       Optab{ASYSCALL, C_REG, C_NONE, C_NONE, C_NONE, 77, 12, 0},
+       Optab{ASYSCALL, C_SCON, C_NONE, C_NONE, C_NONE, 77, 12, 0},
+       Optab{ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 16, 4, 0},
+       Optab{ABEQ, C_CREG, C_NONE, C_NONE, C_SBRA, 16, 4, 0},
+       Optab{ABR, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0},
+       Optab{ABC, C_SCON, C_REG, C_NONE, C_SBRA, 16, 4, 0},
+       Optab{ABC, C_SCON, C_REG, C_NONE, C_LBRA, 17, 4, 0},
+       Optab{ABR, C_NONE, C_NONE, C_NONE, C_LR, 18, 4, 0},
+       Optab{ABR, C_NONE, C_NONE, C_NONE, C_CTR, 18, 4, 0},
+       Optab{ABR, C_REG, C_NONE, C_NONE, C_CTR, 18, 4, 0},
+       Optab{ABR, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0},
+       Optab{ABC, C_NONE, C_REG, C_NONE, C_LR, 18, 4, 0},
+       Optab{ABC, C_NONE, C_REG, C_NONE, C_CTR, 18, 4, 0},
+       Optab{ABC, C_SCON, C_REG, C_NONE, C_LR, 18, 4, 0},
+       Optab{ABC, C_SCON, C_REG, C_NONE, C_CTR, 18, 4, 0},
+       Optab{ABC, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0},
+       Optab{AFMOVD, C_SEXT, C_NONE, C_NONE, C_FREG, 8, 4, REGSB},
+       Optab{AFMOVD, C_SAUTO, C_NONE, C_NONE, C_FREG, 8, 4, REGSP},
+       Optab{AFMOVD, C_SOREG, C_NONE, C_NONE, C_FREG, 8, 4, REGZERO},
+       Optab{AFMOVD, C_LEXT, C_NONE, C_NONE, C_FREG, 36, 8, REGSB},
+       Optab{AFMOVD, C_LAUTO, C_NONE, C_NONE, C_FREG, 36, 8, REGSP},
+       Optab{AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 36, 8, REGZERO},
+       Optab{AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 75, 8, 0},
+       Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+       Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+       Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+       Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+       Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+       Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+       Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+       Optab{ASYNC, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0},
+       Optab{AWORD, C_LCON, C_NONE, C_NONE, C_NONE, 40, 4, 0},
+       Optab{ADWORD, C_LCON, C_NONE, C_NONE, C_NONE, 31, 8, 0},
+       Optab{ADWORD, C_DCON, C_NONE, C_NONE, C_NONE, 31, 8, 0},
+       Optab{AADDME, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0},
+       Optab{AEXTSB, C_REG, C_NONE, C_NONE, C_REG, 48, 4, 0},
+       Optab{AEXTSB, C_NONE, C_NONE, C_NONE, C_REG, 48, 4, 0},
+       Optab{ANEG, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0},
+       Optab{ANEG, C_NONE, C_NONE, C_NONE, C_REG, 47, 4, 0},
+       Optab{AREM, C_REG, C_NONE, C_NONE, C_REG, 50, 12, 0},
+       Optab{AREM, C_REG, C_REG, C_NONE, C_REG, 50, 12, 0},
+       Optab{AREMU, C_REG, C_NONE, C_NONE, C_REG, 50, 16, 0},
+       Optab{AREMU, C_REG, C_REG, C_NONE, C_REG, 50, 16, 0},
+       Optab{AREMD, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0},
+       Optab{AREMD, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0},
+       Optab{AREMDU, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0},
+       Optab{AREMDU, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0},
+       Optab{AMTFSB0, C_SCON, C_NONE, C_NONE, C_NONE, 52, 4, 0},
+       Optab{AMOVFL, C_FPSCR, C_NONE, C_NONE, C_FREG, 53, 4, 0},
+       Optab{AMOVFL, C_FREG, C_NONE, C_NONE, C_FPSCR, 64, 4, 0},
+       Optab{AMOVFL, C_FREG, C_NONE, C_LCON, C_FPSCR, 64, 4, 0},
+       Optab{AMOVFL, C_LCON, C_NONE, C_NONE, C_FPSCR, 65, 4, 0},
+       Optab{AMOVD, C_MSR, C_NONE, C_NONE, C_REG, 54, 4, 0},  /* mfmsr */
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0},  /* mtmsrd */
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0}, /* mtmsr */
+
+       /* 64-bit special registers */
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0},
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LR, 66, 4, 0},
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0},
+       Optab{AMOVD, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0},
+       Optab{AMOVD, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0},
+       Optab{AMOVD, C_LR, C_NONE, C_NONE, C_REG, 66, 4, 0},
+       Optab{AMOVD, C_CTR, C_NONE, C_NONE, C_REG, 66, 4, 0},
+       Optab{AMOVD, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0},
+
+       /* 32-bit special registers (gloss over sign-extension or not?) */
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0},
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0},
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0},
+       Optab{AMOVW, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0},
+       Optab{AMOVW, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0},
+       Optab{AMOVWZ, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0},
+       Optab{AMOVWZ, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0},
+       Optab{AMOVFL, C_FPSCR, C_NONE, C_NONE, C_CREG, 73, 4, 0},
+       Optab{AMOVFL, C_CREG, C_NONE, C_NONE, C_CREG, 67, 4, 0},
+       Optab{AMOVW, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0},
+       Optab{AMOVWZ, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0},
+       Optab{AMOVFL, C_REG, C_NONE, C_LCON, C_CREG, 69, 4, 0},
+       Optab{AMOVFL, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0},
+       Optab{AMOVW, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0},
+       Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0},
+       Optab{ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0},
+       Optab{ACMP, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0},
+       Optab{ACMP, C_REG, C_NONE, C_NONE, C_ADDCON, 71, 4, 0},
+       Optab{ACMP, C_REG, C_REG, C_NONE, C_ADDCON, 71, 4, 0},
+       Optab{ACMPU, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0},
+       Optab{ACMPU, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0},
+       Optab{ACMPU, C_REG, C_NONE, C_NONE, C_ANDCON, 71, 4, 0},
+       Optab{ACMPU, C_REG, C_REG, C_NONE, C_ANDCON, 71, 4, 0},
+       Optab{AFCMPO, C_FREG, C_NONE, C_NONE, C_FREG, 70, 4, 0},
+       Optab{AFCMPO, C_FREG, C_REG, C_NONE, C_FREG, 70, 4, 0},
+       Optab{ATW, C_LCON, C_REG, C_NONE, C_REG, 60, 4, 0},
+       Optab{ATW, C_LCON, C_REG, C_NONE, C_ADDCON, 61, 4, 0},
+       Optab{ADCBF, C_ZOREG, C_NONE, C_NONE, C_NONE, 43, 4, 0},
+       Optab{ADCBF, C_ZOREG, C_REG, C_NONE, C_NONE, 43, 4, 0},
+       Optab{AECOWX, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0},
+       Optab{AECIWX, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0},
+       Optab{AECOWX, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0},
+       Optab{AECIWX, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0},
+       Optab{AEIEIO, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0},
+       Optab{ATLBIE, C_REG, C_NONE, C_NONE, C_NONE, 49, 4, 0},
+       Optab{ATLBIE, C_SCON, C_NONE, C_NONE, C_REG, 49, 4, 0},
+       Optab{ASLBMFEE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0},
+       Optab{ASLBMTE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0},
+       Optab{ASTSW, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0},
+       Optab{ASTSW, C_REG, C_NONE, C_LCON, C_ZOREG, 41, 4, 0},
+       Optab{ALSW, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0},
+       Optab{ALSW, C_ZOREG, C_NONE, C_LCON, C_REG, 42, 4, 0},
+       Optab{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 78, 4, 0},
+       Optab{obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, C_NONE, 0, 0, 0},
+       Optab{obj.APCDATA, C_LCON, C_NONE, C_NONE, C_LCON, 0, 0, 0},
+       Optab{obj.AFUNCDATA, C_SCON, C_NONE, C_NONE, C_ADDR, 0, 0, 0},
+       Optab{obj.ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0},
+       Optab{obj.ADUFFZERO, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0}, // same as ABR/ABL
+       Optab{obj.ADUFFCOPY, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0}, // same as ABR/ABL
+
+       Optab{obj.AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0},
+}
+
+type Oprang struct {
+       start []Optab
+       stop  []Optab
+}
+
+var oprange [ALAST & obj.AMask]Oprang
+
+var xcmp [C_NCLASS][C_NCLASS]uint8
+
+func span9(ctxt *obj.Link, cursym *obj.LSym) {
+       p := cursym.Text
+       if p == nil || p.Link == nil { // handle external functions and ELF section symbols
+               return
+       }
+       ctxt.Cursym = cursym
+       ctxt.Autosize = int32(p.To.Offset + 8)
+
+       if oprange[AANDN&obj.AMask].start == nil {
+               buildop(ctxt)
+       }
+
+       c := int64(0)
+       p.Pc = c
+
+       var m int
+       var o *Optab
+       for p = p.Link; p != nil; p = p.Link {
+               ctxt.Curp = p
+               p.Pc = c
+               o = oplook(ctxt, p)
+               m = int(o.size)
+               if m == 0 {
+                       if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+                               ctxt.Diag("zero-width instruction\n%v", p)
+                       }
+                       continue
+               }
+
+               c += int64(m)
+       }
+
+       cursym.Size = c
+
+       /*
+        * 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
+       for bflag != 0 {
+               if ctxt.Debugvlog != 0 {
+                       fmt.Fprintf(ctxt.Bso, "%5.2f span1\n", obj.Cputime())
+               }
+               bflag = 0
+               c = 0
+               for p = cursym.Text.Link; p != nil; p = p.Link {
+                       p.Pc = c
+                       o = oplook(ctxt, p)
+
+                       // very large conditional branches
+                       if (o.type_ == 16 || o.type_ == 17) && p.Pcond != nil {
+                               otxt = p.Pcond.Pc - c
+                               if otxt < -(1<<15)+10 || otxt >= (1<<15)-10 {
+                                       q = ctxt.NewProg()
+                                       q.Link = p.Link
+                                       p.Link = q
+                                       q.As = ABR
+                                       q.To.Type = obj.TYPE_BRANCH
+                                       q.Pcond = p.Pcond
+                                       p.Pcond = q
+                                       q = ctxt.NewProg()
+                                       q.Link = p.Link
+                                       p.Link = q
+                                       q.As = ABR
+                                       q.To.Type = obj.TYPE_BRANCH
+                                       q.Pcond = q.Link.Link
+
+                                       //addnop(p->link);
+                                       //addnop(p);
+                                       bflag = 1
+                               }
+                       }
+
+                       m = int(o.size)
+                       if m == 0 {
+                               if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+                                       ctxt.Diag("zero-width instruction\n%v", p)
+                               }
+                               continue
+                       }
+
+                       c += int64(m)
+               }
+
+               cursym.Size = c
+       }
+
+       c += -c & (FuncAlign - 1)
+       cursym.Size = c
+
+       /*
+        * lay out the code, emitting code and data relocations.
+        */
+       if ctxt.Tlsg == nil {
+               ctxt.Tlsg = obj.Linklookup(ctxt, "runtime.tlsg", 0)
+       }
+
+       obj.Symgrow(ctxt, cursym, cursym.Size)
+
+       bp := cursym.P
+       var i int32
+       var out [6]uint32
+       for p := cursym.Text.Link; p != nil; p = p.Link {
+               ctxt.Pc = p.Pc
+               ctxt.Curp = p
+               o = oplook(ctxt, 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(ctxt, p, o, out[:])
+               for i = 0; i < int32(o.size/4); i++ {
+                       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 aclass(ctxt *obj.Link, a *obj.Addr) int {
+       switch a.Type {
+       case obj.TYPE_NONE:
+               return C_NONE
+
+       case obj.TYPE_REG:
+               if REG_R0 <= a.Reg && a.Reg <= REG_R31 {
+                       return C_REG
+               }
+               if REG_F0 <= a.Reg && a.Reg <= REG_F31 {
+                       return C_FREG
+               }
+               if REG_CR0 <= a.Reg && a.Reg <= REG_CR7 || a.Reg == REG_CR {
+                       return C_CREG
+               }
+               if REG_SPR0 <= a.Reg && a.Reg <= REG_SPR0+1023 {
+                       switch a.Reg {
+                       case REG_LR:
+                               return C_LR
+
+                       case REG_XER:
+                               return C_XER
+
+                       case REG_CTR:
+                               return C_CTR
+                       }
+
+                       return C_SPR
+               }
+
+               if REG_DCR0 <= a.Reg && a.Reg <= REG_DCR0+1023 {
+                       return C_SPR
+               }
+               if a.Reg == REG_FPSCR {
+                       return C_FPSCR
+               }
+               if a.Reg == REG_MSR {
+                       return C_MSR
+               }
+               return C_GOK
+
+       case obj.TYPE_MEM:
+               switch a.Name {
+               case obj.NAME_EXTERN,
+                       obj.NAME_STATIC:
+                       if a.Sym == nil {
+                               break
+                       }
+                       ctxt.Instoffset = a.Offset
+                       if a.Sym != nil { // use relocation
+                               return C_ADDR
+                       }
+                       return C_LEXT
+
+               case obj.NAME_AUTO:
+                       ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
+                       if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+                               return C_SAUTO
+                       }
+                       return C_LAUTO
+
+               case obj.NAME_PARAM:
+                       ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8
+                       if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+                               return C_SAUTO
+                       }
+                       return C_LAUTO
+
+               case obj.NAME_NONE:
+                       ctxt.Instoffset = a.Offset
+                       if ctxt.Instoffset == 0 {
+                               return C_ZOREG
+                       }
+                       if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+                               return C_SOREG
+                       }
+                       return C_LOREG
+               }
+
+               return C_GOK
+
+       case obj.TYPE_TEXTSIZE:
+               return C_TEXTSIZE
+
+       case obj.TYPE_CONST,
+               obj.TYPE_ADDR:
+               switch a.Name {
+               case obj.TYPE_NONE:
+                       ctxt.Instoffset = a.Offset
+                       if a.Reg != 0 {
+                               if -BIG <= ctxt.Instoffset && ctxt.Instoffset <= BIG {
+                                       return C_SACON
+                               }
+                               if isint32(ctxt.Instoffset) {
+                                       return C_LACON
+                               }
+                               return C_DACON
+                       }
+
+                       goto consize
+
+               case obj.NAME_EXTERN,
+                       obj.NAME_STATIC:
+                       s := a.Sym
+                       if s == nil {
+                               break
+                       }
+                       if s.Type == obj.SCONST {
+                               ctxt.Instoffset = s.Value + a.Offset
+                               goto consize
+                       }
+
+                       ctxt.Instoffset = s.Value + a.Offset
+
+                       /* not sure why this barfs */
+                       return C_LCON
+
+               case obj.NAME_AUTO:
+                       ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
+                       if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+                               return C_SACON
+                       }
+                       return C_LACON
+
+               case obj.NAME_PARAM:
+                       ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8
+                       if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+                               return C_SACON
+                       }
+                       return C_LACON
+               }
+
+               return C_GOK
+
+       consize:
+               if ctxt.Instoffset >= 0 {
+                       if ctxt.Instoffset == 0 {
+                               return C_ZCON
+                       }
+                       if ctxt.Instoffset <= 0x7fff {
+                               return C_SCON
+                       }
+                       if ctxt.Instoffset <= 0xffff {
+                               return C_ANDCON
+                       }
+                       if ctxt.Instoffset&0xffff == 0 && isuint32(uint64(ctxt.Instoffset)) { /* && (instoffset & (1<<31)) == 0) */
+                               return C_UCON
+                       }
+                       if isint32(ctxt.Instoffset) || isuint32(uint64(ctxt.Instoffset)) {
+                               return C_LCON
+                       }
+                       return C_DCON
+               }
+
+               if ctxt.Instoffset >= -0x8000 {
+                       return C_ADDCON
+               }
+               if ctxt.Instoffset&0xffff == 0 && isint32(ctxt.Instoffset) {
+                       return C_UCON
+               }
+               if isint32(ctxt.Instoffset) {
+                       return C_LCON
+               }
+               return C_DCON
+
+       case obj.TYPE_BRANCH:
+               return C_SBRA
+       }
+
+       return C_GOK
+}
+
+func prasm(p *obj.Prog) {
+       fmt.Printf("%v\n", p)
+}
+
+func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
+       a1 := int(p.Optab)
+       if a1 != 0 {
+               return &optab[a1-1:][0]
+       }
+       a1 = int(p.From.Class)
+       if a1 == 0 {
+               a1 = aclass(ctxt, &p.From) + 1
+               p.From.Class = int8(a1)
+       }
+
+       a1--
+       a3 := C_NONE + 1
+       if p.From3 != nil {
+               a3 = int(p.From3.Class)
+               if a3 == 0 {
+                       a3 = aclass(ctxt, p.From3) + 1
+                       p.From3.Class = int8(a3)
+               }
+       }
+
+       a3--
+       a4 := int(p.To.Class)
+       if a4 == 0 {
+               a4 = aclass(ctxt, &p.To) + 1
+               p.To.Class = int8(a4)
+       }
+
+       a4--
+       a2 := C_NONE
+       if p.Reg != 0 {
+               a2 = C_REG
+       }
+
+       //print("oplook %v %d %d %d %d\n", p, a1, a2, a3, a4);
+       r0 := p.As & obj.AMask
+
+       o := oprange[r0].start
+       if o == nil {
+               o = oprange[r0].stop /* just generate an error */
+       }
+       e := oprange[r0].stop
+       c1 := xcmp[a1][:]
+       c3 := xcmp[a3][:]
+       c4 := xcmp[a4][:]
+       for ; -cap(o) < -cap(e); o = o[1:] {
+               if int(o[0].a2) == a2 {
+                       if c1[o[0].a1] != 0 {
+                               if c3[o[0].a3] != 0 {
+                                       if c4[o[0].a4] != 0 {
+                                               p.Optab = uint16((-cap(o) + cap(optab)) + 1)
+                                               return &o[0]
+                                       }
+                               }
+                       }
+               }
+       }
+
+       ctxt.Diag("illegal combination %v %v %v %v %v", obj.Aconv(int(p.As)), DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
+       prasm(p)
+       if o == nil {
+               o = optab
+       }
+       return &o[0]
+}
+
+func cmp(a int, b int) bool {
+       if a == b {
+               return true
+       }
+       switch a {
+       case C_LCON:
+               if b == C_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON {
+                       return true
+               }
+
+       case C_ADDCON:
+               if b == C_ZCON || b == C_SCON {
+                       return true
+               }
+
+       case C_ANDCON:
+               if b == C_ZCON || b == C_SCON {
+                       return true
+               }
+
+       case C_SPR:
+               if b == C_LR || b == C_XER || b == C_CTR {
+                       return true
+               }
+
+       case C_UCON:
+               if b == C_ZCON {
+                       return true
+               }
+
+       case C_SCON:
+               if b == C_ZCON {
+                       return true
+               }
+
+       case C_LACON:
+               if b == C_SACON {
+                       return true
+               }
+
+       case C_LBRA:
+               if b == C_SBRA {
+                       return true
+               }
+
+       case C_LEXT:
+               if b == C_SEXT {
+                       return true
+               }
+
+       case C_LAUTO:
+               if b == C_SAUTO {
+                       return true
+               }
+
+       case C_REG:
+               if b == C_ZCON {
+                       return r0iszero != 0 /*TypeKind(100016)*/
+               }
+
+       case C_LOREG:
+               if b == C_ZOREG || b == C_SOREG {
+                       return true
+               }
+
+       case C_SOREG:
+               if b == C_ZOREG {
+                       return true
+               }
+
+       case C_ANY:
+               return true
+       }
+
+       return false
+}
+
+type ocmp []Optab
+
+func (x ocmp) Len() int {
+       return len(x)
+}
+
+func (x ocmp) Swap(i, j int) {
+       x[i], x[j] = x[j], x[i]
+}
+
+func (x ocmp) Less(i, j int) bool {
+       p1 := &x[i]
+       p2 := &x[j]
+       n := int(p1.as) - int(p2.as)
+       if n != 0 {
+               return n < 0
+       }
+       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
+       }
+       return false
+}
+func opset(a, b0 int16) {
+       oprange[a&obj.AMask] = oprange[b0]
+}
+
+func buildop(ctxt *obj.Link) {
+       var n int
+
+       for i := 0; i < C_NCLASS; i++ {
+               for n = 0; n < C_NCLASS; n++ {
+                       if cmp(n, i) {
+                               xcmp[i][n] = 1
+                       }
+               }
+       }
+       for n = 0; optab[n].as != obj.AXXX; n++ {
+       }
+       sort.Sort(ocmp(optab[:n]))
+       for i := 0; i < n; i++ {
+               r := optab[i].as
+               r0 := r & obj.AMask
+               oprange[r0].start = optab[i:]
+               for optab[i].as == r {
+                       i++
+               }
+               oprange[r0].stop = optab[i:]
+               i--
+
+               switch r {
+               default:
+                       ctxt.Diag("unknown op in build: %v", obj.Aconv(int(r)))
+                       log.Fatalf("bad code")
+
+               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 AECOWX: /* indexed store: op s,(b+a); op s,(b) */
+                       opset(ASTWCCC, r0)
+
+                       opset(ASTDCCC, r0)
+
+               case AREM: /* macro */
+                       opset(AREMCC, r0)
+
+                       opset(AREMV, r0)
+                       opset(AREMVCC, r0)
+
+               case AREMU:
+                       opset(AREMU, r0)
+                       opset(AREMUCC, r0)
+                       opset(AREMUV, r0)
+                       opset(AREMUVCC, r0)
+
+               case AREMD:
+                       opset(AREMDCC, r0)
+                       opset(AREMDV, r0)
+                       opset(AREMDVCC, r0)
+
+               case AREMDU:
+                       opset(AREMDU, r0)
+                       opset(AREMDUCC, r0)
+                       opset(AREMDUV, r0)
+                       opset(AREMDUVCC, 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(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(ACRAND, r0)
+                       opset(ACRANDN, r0)
+                       opset(ACREQV, r0)
+                       opset(ACRNAND, r0)
+                       opset(ACRNOR, r0)
+                       opset(ACROR, r0)
+                       opset(ACRORN, r0)
+                       opset(ACRXOR, r0)
+                       opset(AMULHD, r0)
+                       opset(AMULHDCC, r0)
+                       opset(AMULHDU, r0)
+                       opset(AMULHDUCC, r0)
+                       opset(AMULLD, r0)
+                       opset(AMULLDCC, r0)
+                       opset(AMULLDVCC, r0)
+                       opset(AMULLDV, r0)
+                       opset(ADIVD, r0)
+                       opset(ADIVDCC, r0)
+                       opset(ADIVDVCC, r0)
+                       opset(ADIVDV, r0)
+                       opset(ADIVDU, r0)
+                       opset(ADIVDUCC, r0)
+                       opset(ADIVDUVCC, r0)
+                       opset(ADIVDUCC, 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 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 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(AFRES, r0)
+                       opset(AFRESCC, 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(AFDIV, r0)
+                       opset(AFDIVS, r0)
+                       opset(AFDIVCC, r0)
+                       opset(AFDIVSCC, r0)
+                       opset(AFSUB, r0)
+                       opset(AFSUBS, r0)
+                       opset(AFSUBCC, r0)
+                       opset(AFSUBSCC, 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)
+
+               case AFCMPO:
+                       opset(AFCMPU, 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,Ra; oris/xoris $uimm,Rs,Ra */
+                       opset(AXOR, r0)
+
+               case ASLW:
+                       opset(ASLWCC, r0)
+                       opset(ASRW, r0)
+                       opset(ASRWCC, r0)
+
+               case ASLD:
+                       opset(ASLDCC, r0)
+                       opset(ASRD, r0)
+                       opset(ASRDCC, r0)
+
+               case ASRAW: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
+                       opset(ASRAWCC, 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(APTESYNC, r0)
+                       opset(ATLBSYNC, r0)
+
+               case ARLWMI:
+                       opset(ARLWMICC, r0)
+                       opset(ARLWNM, r0)
+                       opset(ARLWNMCC, r0)
+
+               case ARLDMI:
+                       opset(ARLDMICC, r0)
+
+               case ARLDC:
+                       opset(ARLDCCC, r0)
+
+               case ARLDCL:
+                       opset(ARLDCR, r0)
+                       opset(ARLDCLCC, r0)
+                       opset(ARLDCRCC, r0)
+
+               case AFMOVD:
+                       opset(AFMOVDCC, r0)
+                       opset(AFMOVDU, r0)
+                       opset(AFMOVS, r0)
+                       opset(AFMOVSU, r0)
+
+               case AECIWX:
+                       opset(ALWAR, r0)
+                       opset(ALDAR, 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)
+
+               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 AADD,
+                       AANDCC, /* and. Rb,Rs,Ra; andi. $uimm,Rs,Ra; andis. $uimm,Rs,Ra */
+                       ALSW,
+                       AMOVW,
+                       /* load/store/move word with sign extension; special 32-bit move; move 32-bit literals */
+                       AMOVWZ, /* load/store/move word with zero extension; move 32-bit literals  */
+                       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,
+                       AMULLW,
+                       /* op $s[,r2],r3; op r1[,r2],r3; no cc/v */
+                       ASUBC, /* op r1,$s,r3; op r1[,r2],r3 */
+                       ASTSW,
+                       ASLBMTE,
+                       AWORD,
+                       ADWORD,
+                       obj.ANOP,
+                       obj.ATEXT,
+                       obj.AUNDEF,
+                       obj.AUSEFIELD,
+                       obj.AFUNCDATA,
+                       obj.APCDATA,
+                       obj.ADUFFZERO,
+                       obj.ADUFFCOPY:
+                       break
+               }
+       }
+}
+
+func OPVCC(o uint32, xo uint32, oe uint32, rc uint32) uint32 {
+       return o<<26 | xo<<1 | oe<<10 | rc&1
+}
+
+func OPCC(o uint32, xo uint32, rc uint32) uint32 {
+       return OPVCC(o, xo, 0, rc)
+}
+
+func OP(o uint32, xo uint32) uint32 {
+       return OPVCC(o, xo, 0, 0)
+}
+
+/* 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
+}
+
+func AOP_IRR(op uint32, d uint32, a uint32, simm uint32) uint32 {
+       return op | (d&31)<<21 | (a&31)<<16 | simm&0xFFFF
+}
+
+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
+}
+
+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_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_MFMSR  = 31<<26 | 83<<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_MTMSR  = 31<<26 | 146<<1 | 0<<10 | 0
+       OP_MTMSRD = 31<<26 | 178<<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_RLWINM = 21<<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
+)
+
+func oclass(a *obj.Addr) int {
+       return int(a.Class) - 1
+}
+
+// add R_ADDRPOWER relocation to symbol s for the two instructions o1 and o2.
+func addaddrreloc(ctxt *obj.Link, s *obj.LSym, o1 *uint32, o2 *uint32) {
+       rel := obj.Addrel(ctxt.Cursym)
+       rel.Off = int32(ctxt.Pc)
+       rel.Siz = 8
+       rel.Sym = s
+       rel.Add = int64(uint64(*o1)<<32 | uint64(uint32(*o2)))
+       rel.Type = obj.R_ADDRPOWER
+}
+
+/*
+ * 32-bit masks
+ */
+func getmask(m []byte, v uint32) bool {
+       m[1] = 0
+       m[0] = m[1]
+       if v != ^uint32(0) && v&(1<<31) != 0 && v&1 != 0 { /* MB > ME */
+               if getmask(m, ^v) {
+                       i := int(m[0])
+                       m[0] = m[1] + 1
+                       m[1] = byte(i - 1)
+                       return true
+               }
+
+               return false
+       }
+
+       for i := 0; i < 32; i++ {
+               if v&(1<<uint(31-i)) != 0 {
+                       m[0] = byte(i)
+                       for {
+                               m[1] = byte(i)
+                               i++
+                               if i >= 32 || v&(1<<uint(31-i)) == 0 {
+                                       break
+                               }
+                       }
+
+                       for ; i < 32; i++ {
+                               if v&(1<<uint(31-i)) != 0 {
+                                       return false
+                               }
+                       }
+                       return true
+               }
+       }
+
+       return false
+}
+
+func maskgen(ctxt *obj.Link, p *obj.Prog, m []byte, v uint32) {
+       if !getmask(m, v) {
+               ctxt.Diag("cannot generate mask #%x\n%v", v, p)
+       }
+}
+
+/*
+ * 64-bit masks (rldic etc)
+ */
+func getmask64(m []byte, v uint64) bool {
+       m[1] = 0
+       m[0] = m[1]
+       for i := 0; i < 64; i++ {
+               if v&(uint64(1)<<uint(63-i)) != 0 {
+                       m[0] = byte(i)
+                       for {
+                               m[1] = byte(i)
+                               i++
+                               if i >= 64 || v&(uint64(1)<<uint(63-i)) == 0 {
+                                       break
+                               }
+                       }
+
+                       for ; i < 64; i++ {
+                               if v&(uint64(1)<<uint(63-i)) != 0 {
+                                       return false
+                               }
+                       }
+                       return true
+               }
+       }
+
+       return false
+}
+
+func maskgen64(ctxt *obj.Link, p *obj.Prog, m []byte, v uint64) {
+       if !getmask64(m, v) {
+               ctxt.Diag("cannot generate mask #%x\n%v", v, p)
+       }
+}
+
+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(ctxt *obj.Link, p *obj.Prog, o *Optab, out []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:
+               ctxt.Diag("unknown type %d", o.type_)
+               prasm(p)
+
+       case 0: /* pseudo ops */
+               break
+
+       case 1: /* mov r1,r2 ==> OR Rs,Rs,Ra */
+               if p.To.Reg == REGZERO && p.From.Type == obj.TYPE_CONST {
+                       v := regoff(ctxt, &p.From)
+                       if r0iszero != 0 /*TypeKind(100016)*/ && v != 0 {
+                               //nerrors--;
+                               ctxt.Diag("literal operation on R0\n%v", p)
+                       }
+
+                       o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, uint32(v))
+                       break
+               }
+
+               o1 = LOP_RRR(OP_OR, uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.From.Reg))
+
+       case 2: /* int/cr/fp op Rb,[Ra],Rd */
+               r := int(p.Reg)
+
+               if r == 0 {
+                       r = int(p.To.Reg)
+               }
+               o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
+
+       case 3: /* mov $soreg/addcon/ucon, r ==> addis/addi $i,reg',r */
+               d := vregoff(ctxt, &p.From)
+
+               v := int32(d)
+               r := int(p.From.Reg)
+               if r == 0 {
+                       r = int(o.param)
+               }
+               if r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0 && (r != 0 || v != 0) {
+                       ctxt.Diag("literal operation on R0\n%v", p)
+               }
+               a := OP_ADDI
+               if o.a1 == C_UCON {
+                       if d&0xffff != 0 {
+                               log.Fatalf("invalid handling of %v", p)
+                       }
+                       v >>= 16
+                       if r == REGZERO && isuint32(uint64(d)) {
+                               o1 = LOP_IRR(OP_ORIS, uint32(p.To.Reg), REGZERO, uint32(v))
+                               break
+                       }
+
+                       a = OP_ADDIS
+               } else {
+                       if int64(int16(d)) != d {
+                               log.Fatalf("invalid handling of %v", p)
+                       }
+               }
+
+               o1 = AOP_IRR(uint32(a), uint32(p.To.Reg), uint32(r), uint32(v))
+
+       case 4: /* add/mul $scon,[r1],r2 */
+               v := regoff(ctxt, &p.From)
+
+               r := int(p.Reg)
+               if r == 0 {
+                       r = int(p.To.Reg)
+               }
+               if r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0 {
+                       ctxt.Diag("literal operation on R0\n%v", p)
+               }
+               if int32(int16(v)) != v {
+                       log.Fatalf("mishandled instruction %v", p)
+               }
+               o1 = AOP_IRR(uint32(opirr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(v))
+
+       case 5: /* syscall */
+               o1 = uint32(oprrr(ctxt, int(p.As)))
+
+       case 6: /* logical op Rb,[Rs,]Ra; no literal */
+               r := int(p.Reg)
+
+               if r == 0 {
+                       r = int(p.To.Reg)
+               }
+               o1 = LOP_RRR(uint32(oprrr(ctxt, int(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)
+
+               if r == 0 {
+                       r = int(o.param)
+               }
+               v := regoff(ctxt, &p.To)
+               if p.To.Type == obj.TYPE_MEM && p.To.Index != 0 {
+                       if v != 0 {
+                               ctxt.Diag("illegal indexed instruction\n%v", p)
+                       }
+                       o1 = AOP_RRR(uint32(opstorex(ctxt, int(p.As))), uint32(p.From.Reg), uint32(p.To.Index), uint32(r))
+               } else {
+                       if int32(int16(v)) != v {
+                               log.Fatalf("mishandled instruction %v", p)
+                       }
+                       o1 = AOP_IRR(uint32(opstore(ctxt, int(p.As))), uint32(p.From.Reg), uint32(r), uint32(v))
+               }
+
+       case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */
+               r := int(p.From.Reg)
+
+               if r == 0 {
+                       r = int(o.param)
+               }
+               v := regoff(ctxt, &p.From)
+               if p.From.Type == obj.TYPE_MEM && p.From.Index != 0 {
+                       if v != 0 {
+                               ctxt.Diag("illegal indexed instruction\n%v", p)
+                       }
+                       o1 = AOP_RRR(uint32(oploadx(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Index), uint32(r))
+               } else {
+                       if int32(int16(v)) != v {
+                               log.Fatalf("mishandled instruction %v", p)
+                       }
+                       o1 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(v))
+               }
+
+       case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */
+               r := int(p.From.Reg)
+
+               if r == 0 {
+                       r = int(o.param)
+               }
+               v := regoff(ctxt, &p.From)
+               if p.From.Type == obj.TYPE_MEM && p.From.Index != 0 {
+                       if v != 0 {
+                               ctxt.Diag("illegal indexed instruction\n%v", p)
+                       }
+                       o1 = AOP_RRR(uint32(oploadx(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Index), uint32(r))
+               } else {
+                       o1 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(v))
+               }
+               o2 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
+
+       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(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Reg), uint32(r))
+
+       case 11: /* br/bl lbra */
+               v := int32(0)
+
+               if p.Pcond != nil {
+                       v = int32(p.Pcond.Pc - p.Pc)
+                       if v&03 != 0 {
+                               ctxt.Diag("odd branch target address\n%v", p)
+                               v &^= 03
+                       }
+
+                       if v < -(1<<25) || v >= 1<<24 {
+                               ctxt.Diag("branch too far\n%v", p)
+                       }
+               }
+
+               o1 = OP_BR(uint32(opirr(ctxt, int(p.As))), uint32(v), 0)
+               if p.To.Sym != nil {
+                       rel := obj.Addrel(ctxt.Cursym)
+                       rel.Off = int32(ctxt.Pc)
+                       rel.Siz = 4
+                       rel.Sym = p.To.Sym
+                       v += int32(p.To.Offset)
+                       if v&03 != 0 {
+                               ctxt.Diag("odd branch target address\n%v", p)
+                               v &^= 03
+                       }
+
+                       rel.Add = int64(v)
+                       rel.Type = obj.R_CALLPOWER
+               }
+
+       case 12: /* movb r,r (extsb); movw r,r (extsw) */
+               if p.To.Reg == REGZERO && p.From.Type == obj.TYPE_CONST {
+                       v := regoff(ctxt, &p.From)
+                       if r0iszero != 0 /*TypeKind(100016)*/ && v != 0 {
+                               ctxt.Diag("literal operation on R0\n%v", p)
+                       }
+
+                       o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, uint32(v))
+                       break
+               }
+
+               if p.As == AMOVW {
+                       o1 = LOP_RRR(OP_EXTSW, uint32(p.To.Reg), uint32(p.From.Reg), 0)
+               } else {
+                       o1 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.From.Reg), 0)
+               }
+
+       case 13: /* mov[bhw]z r,r; uses rlwinm not andi. to avoid changing CC */
+               if p.As == AMOVBZ {
+                       o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.From.Reg), 0, 24, 31)
+               } else if p.As == AMOVH {
+                       o1 = LOP_RRR(OP_EXTSH, uint32(p.To.Reg), uint32(p.From.Reg), 0)
+               } else if p.As == AMOVHZ {
+                       o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.From.Reg), 0, 16, 31)
+               } else if p.As == AMOVWZ {
+                       o1 = OP_RLW(OP_RLDIC, uint32(p.To.Reg), uint32(p.From.Reg), 0, 0, 0) | 1<<5 /* MB=32 */
+               } else {
+                       ctxt.Diag("internal: bad mov[bhw]z\n%v", p)
+               }
+
+       case 14: /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */
+               r := int(p.Reg)
+
+               if r == 0 {
+                       r = int(p.To.Reg)
+               }
+               d := vregoff(ctxt, p.From3)
+               var mask [2]uint8
+               maskgen64(ctxt, p, mask[:], uint64(d))
+               var a int
+               switch p.As {
+               case ARLDCL, ARLDCLCC:
+                       a = int(mask[0]) /* MB */
+                       if mask[1] != 63 {
+                               ctxt.Diag("invalid mask for rotate: %x (end != bit 63)\n%v", uint64(d), p)
+                       }
+
+               case ARLDCR, ARLDCRCC:
+                       a = int(mask[1]) /* ME */
+                       if mask[0] != 0 {
+                               ctxt.Diag("invalid mask for rotate: %x (start != 0)\n%v", uint64(d), p)
+                       }
+
+               default:
+                       ctxt.Diag("unexpected op in rldc case\n%v", p)
+                       a = 0
+               }
+
+               o1 = LOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
+               o1 |= (uint32(a) & 31) << 6
+               if a&0x20 != 0 {
+                       o1 |= 1 << 5 /* mb[5] is top bit */
+               }
+
+       case 17, /* bc bo,bi,lbra (same for now) */
+               16: /* bc bo,bi,sbra */
+               a := 0
+
+               if p.From.Type == obj.TYPE_CONST {
+                       a = int(regoff(ctxt, &p.From))
+               }
+               r := int(p.Reg)
+               if r == 0 {
+                       r = 0
+               }
+               v := int32(0)
+               if p.Pcond != nil {
+                       v = int32(p.Pcond.Pc - p.Pc)
+               }
+               if v&03 != 0 {
+                       ctxt.Diag("odd branch target address\n%v", p)
+                       v &^= 03
+               }
+
+               if v < -(1<<16) || v >= 1<<15 {
+                       ctxt.Diag("branch too far\n%v", p)
+               }
+               o1 = OP_BC(uint32(opirr(ctxt, int(p.As))), uint32(a), uint32(r), uint32(v), 0)
+
+       case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */
+               var v int32
+               if p.As == ABC || p.As == ABCL {
+                       v = regoff(ctxt, &p.To) & 31
+               } else {
+                       v = 20 /* unconditional */
+               }
+               o1 = AOP_RRR(OP_MTSPR, uint32(p.To.Reg), 0, 0) | (REG_LR&0x1f)<<16 | ((REG_LR>>5)&0x1f)<<11
+               o2 = OPVCC(19, 16, 0, 0)
+               if p.As == ABL || p.As == ABCL {
+                       o2 |= 1
+               }
+               o2 = OP_BCR(o2, uint32(v), uint32(p.To.Index))
+
+       case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */
+               var v int32
+               if p.As == ABC || p.As == ABCL {
+                       v = regoff(ctxt, &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:
+                       ctxt.Diag("bad optab entry (18): %d\n%v", p.To.Class, p)
+                       v = 0
+               }
+
+               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 := vregoff(ctxt, &p.From)
+
+               if p.From.Sym == nil {
+                       o1 = loadu32(int(p.To.Reg), d)
+                       o2 = LOP_IRR(OP_ORI, uint32(p.To.Reg), uint32(p.To.Reg), uint32(int32(d)))
+               } else {
+                       o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(high16adjusted(int32(d))))
+                       o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(d))
+                       addaddrreloc(ctxt, p.From.Sym, &o1, &o2)
+               }
+
+       //if(dlm) reloc(&p->from, p->pc, 0);
+
+       case 20: /* add $ucon,,r */
+               v := regoff(ctxt, &p.From)
+
+               r := int(p.Reg)
+               if r == 0 {
+                       r = int(p.To.Reg)
+               }
+               if p.As == AADD && (r0iszero == 0 /*TypeKind(100016)*/ && p.Reg == 0 || r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0) {
+                       ctxt.Diag("literal operation on R0\n%v", p)
+               }
+               o1 = AOP_IRR(uint32(opirr(ctxt, int(p.As)+ALAST)), uint32(p.To.Reg), uint32(r), uint32(v)>>16)
+
+       case 22: /* add $lcon,r1,r2 ==> cau+or+add */ /* could do add/sub more efficiently */
+               if p.To.Reg == REGTMP || p.Reg == REGTMP {
+                       ctxt.Diag("cant synthesize large constant\n%v", p)
+               }
+               d := vregoff(ctxt, &p.From)
+               o1 = loadu32(REGTMP, d)
+               o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))
+               r := int(p.Reg)
+               if r == 0 {
+                       r = int(p.To.Reg)
+               }
+               o3 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(r))
+               if p.From.Sym != nil {
+                       ctxt.Diag("%v is not supported", p)
+               }
+
+       //if(dlm) reloc(&p->from, p->pc, 0);
+
+       case 23: /* and $lcon,r1,r2 ==> cau+or+and */ /* masks could be done using rlnm etc. */
+               if p.To.Reg == REGTMP || p.Reg == REGTMP {
+                       ctxt.Diag("cant synthesize large constant\n%v", p)
+               }
+               d := vregoff(ctxt, &p.From)
+               o1 = loadu32(REGTMP, d)
+               o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))
+               r := int(p.Reg)
+               if r == 0 {
+                       r = int(p.To.Reg)
+               }
+               o3 = LOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(r))
+               if p.From.Sym != nil {
+                       ctxt.Diag("%v is not supported", p)
+               }
+
+               //if(dlm) reloc(&p->from, p->pc, 0);
+
+               /*24*/
+       case 25:
+               /* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */
+               v := regoff(ctxt, &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
+               switch p.As {
+               case ASLD, ASLDCC:
+                       a = int(63 - v)
+                       o1 = OP_RLDICR
+
+               case ASRD, ASRDCC:
+                       a = int(v)
+                       v = 64 - v
+                       o1 = OP_RLDICL
+
+               default:
+                       ctxt.Diag("unexpected op in sldi case\n%v", p)
+                       a = 0
+                       o1 = 0
+               }
+
+               o1 = AOP_RRR(o1, uint32(r), uint32(p.To.Reg), (uint32(v) & 0x1F))
+               o1 |= (uint32(a) & 31) << 6
+               if v&0x20 != 0 {
+                       o1 |= 1 << 1
+               }
+               if a&0x20 != 0 {
+                       o1 |= 1 << 5 /* mb[5] is top bit */
+               }
+               if p.As == ASLDCC || p.As == ASRDCC {
+                       o1 |= 1 /* Rc */
+               }
+
+       case 26: /* mov $lsext/auto/oreg,,r2 ==> addis+addi */
+               if p.To.Reg == REGTMP {
+                       ctxt.Diag("can't synthesize large constant\n%v", p)
+               }
+               v := regoff(ctxt, &p.From)
+               r := int(p.From.Reg)
+               if r == 0 {
+                       r = int(o.param)
+               }
+               o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
+               o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(v))
+
+       case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
+               v := regoff(ctxt, p.From3)
+
+               r := int(p.From.Reg)
+               o1 = AOP_IRR(uint32(opirr(ctxt, int(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 {
+                       ctxt.Diag("can't synthesize large constant\n%v", p)
+               }
+               v := regoff(ctxt, p.From3)
+               o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(v)>>16)
+               o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(v))
+               o3 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Reg), REGTMP)
+               if p.From.Sym != nil {
+                       ctxt.Diag("%v is not supported", p)
+               }
+
+       //if(dlm) reloc(&p->from3, p->pc, 0);
+
+       case 29: /* rldic[lr]? $sh,s,$mask,a -- left, right, plain give different masks */
+               v := regoff(ctxt, &p.From)
+
+               d := vregoff(ctxt, p.From3)
+               var mask [2]uint8
+               maskgen64(ctxt, p, mask[:], uint64(d))
+               var a int
+               switch p.As {
+               case ARLDC, ARLDCCC:
+                       a = int(mask[0]) /* MB */
+                       if int32(mask[1]) != (63 - v) {
+                               ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
+                       }
+
+               case ARLDCL, ARLDCLCC:
+                       a = int(mask[0]) /* MB */
+                       if mask[1] != 63 {
+                               ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
+                       }
+
+               case ARLDCR, ARLDCRCC:
+                       a = int(mask[1]) /* ME */
+                       if mask[0] != 0 {
+                               ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
+                       }
+
+               default:
+                       ctxt.Diag("unexpected op in rldic case\n%v", p)
+                       a = 0
+               }
+
+               o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
+               o1 |= (uint32(a) & 31) << 6
+               if v&0x20 != 0 {
+                       o1 |= 1 << 1
+               }
+               if a&0x20 != 0 {
+                       o1 |= 1 << 5 /* mb[5] is top bit */
+               }
+
+       case 30: /* rldimi $sh,s,$mask,a */
+               v := regoff(ctxt, &p.From)
+
+               d := vregoff(ctxt, p.From3)
+               var mask [2]uint8
+               maskgen64(ctxt, p, mask[:], uint64(d))
+               if int32(mask[1]) != (63 - v) {
+                       ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
+               }
+               o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
+               o1 |= (uint32(mask[0]) & 31) << 6
+               if v&0x20 != 0 {
+                       o1 |= 1 << 1
+               }
+               if mask[0]&0x20 != 0 {
+                       o1 |= 1 << 5 /* mb[5] is top bit */
+               }
+
+       case 31: /* dword */
+               d := vregoff(ctxt, &p.From)
+
+               if 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 {
+                       rel := obj.Addrel(ctxt.Cursym)
+                       rel.Off = int32(ctxt.Pc)
+                       rel.Siz = 8
+                       rel.Sym = p.From.Sym
+                       rel.Add = p.From.Offset
+                       rel.Type = obj.R_ADDR
+                       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(uint32(oprrr(ctxt, int(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(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), 0, uint32(r))
+
+       case 34: /* FMADDx fra,frb,frc,frd (d=a*b+c); FSELx a<0? (d=b): (d=c) */
+               o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg)) | (uint32(p.From3.Reg)&31)<<6
+
+       case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */
+               v := regoff(ctxt, &p.To)
+
+               r := int(p.To.Reg)
+               if r == 0 {
+                       r = int(o.param)
+               }
+               o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
+               o2 = AOP_IRR(uint32(opstore(ctxt, int(p.As))), uint32(p.From.Reg), REGTMP, uint32(v))
+
+       case 36: /* mov bz/h/hz lext/lauto/lreg,r ==> lbz/lha/lhz etc */
+               v := regoff(ctxt, &p.From)
+
+               r := int(p.From.Reg)
+               if r == 0 {
+                       r = int(o.param)
+               }
+               o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
+               o2 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(v))
+
+       case 37: /* movb lext/lauto/lreg,r ==> lbz o(reg),r; extsb r */
+               v := regoff(ctxt, &p.From)
+
+               r := int(p.From.Reg)
+               if r == 0 {
+                       r = int(o.param)
+               }
+               o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
+               o2 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(v))
+               o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
+
+       case 40: /* word */
+               o1 = uint32(regoff(ctxt, &p.From))
+
+       case 41: /* stswi */
+               o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.From.Reg), uint32(p.To.Reg), 0) | (uint32(regoff(ctxt, p.From3))&0x7F)<<11
+
+       case 42: /* lswi */
+               o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Reg), 0) | (uint32(regoff(ctxt, p.From3))&0x7F)<<11
+
+       case 43: /* unary indexed source: dcbf (b); dcbf (a+b) */
+               o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), 0, uint32(p.From.Index), uint32(p.From.Reg))
+
+       case 44: /* indexed store */
+               o1 = AOP_RRR(uint32(opstorex(ctxt, int(p.As))), uint32(p.From.Reg), uint32(p.To.Index), uint32(p.To.Reg))
+
+       case 45: /* indexed load */
+               o1 = AOP_RRR(uint32(oploadx(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
+
+       case 46: /* plain op */
+               o1 = uint32(oprrr(ctxt, int(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(uint32(oprrr(ctxt, int(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(uint32(oprrr(ctxt, int(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 := regoff(ctxt, &p.From) & 1
+                       o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), 0, 0, uint32(p.To.Reg)) | uint32(v)<<21
+               } else {
+                       o1 = AOP_RRR(uint32(oprrr(ctxt, int(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 := oprrr(ctxt, int(p.As))
+               t := v & (1<<10 | 1) /* OE|Rc */
+               o1 = AOP_RRR(uint32(v)&^uint32(t), REGTMP, uint32(r), uint32(p.From.Reg))
+               o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, uint32(p.From.Reg))
+               o3 = AOP_RRR(OP_SUBF|uint32(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 := oprrr(ctxt, int(p.As))
+               t := v & (1<<10 | 1) /* OE|Rc */
+               o1 = AOP_RRR(uint32(v)&^uint32(t), REGTMP, uint32(r), uint32(p.From.Reg))
+               o2 = AOP_RRR(OP_MULLD, REGTMP, REGTMP, uint32(p.From.Reg))
+               o3 = AOP_RRR(OP_SUBF|uint32(t), uint32(p.To.Reg), REGTMP, uint32(r))
+
+       case 52: /* mtfsbNx cr(n) */
+               v := regoff(ctxt, &p.From) & 31
+
+               o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(v), 0, 0)
+
+       case 53: /* mffsX ,fr1 */
+               o1 = AOP_RRR(OP_MFFS, uint32(p.To.Reg), 0, 0)
+
+       case 54: /* mov msr,r1; mov r1, msr*/
+               if oclass(&p.From) == C_REG {
+                       if p.As == AMOVD {
+                               o1 = AOP_RRR(OP_MTMSRD, uint32(p.From.Reg), 0, 0)
+                       } else {
+                               o1 = AOP_RRR(OP_MTMSR, uint32(p.From.Reg), 0, 0)
+                       }
+               } else {
+                       o1 = AOP_RRR(OP_MFMSR, uint32(p.To.Reg), 0, 0)
+               }
+
+       case 55: /* op Rb, Rd */
+               o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), 0, uint32(p.From.Reg))
+
+       case 56: /* sra $sh,[s,]a; srd $sh,[s,]a */
+               v := regoff(ctxt, &p.From)
+
+               r := int(p.Reg)
+               if r == 0 {
+                       r = int(p.To.Reg)
+               }
+               o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(r), uint32(p.To.Reg), uint32(v)&31)
+               if p.As == ASRAD && (v&0x20 != 0) {
+                       o1 |= 1 << 1 /* mb[5] */
+               }
+
+       case 57: /* slw $sh,[s,]a -> rlwinm ... */
+               v := regoff(ctxt, &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
+               if p.As == ASRW || p.As == ASRWCC { /* shift right */
+                       mask[0] = uint8(v)
+                       mask[1] = 31
+                       v = 32 - v
+               } else {
+                       mask[0] = 0
+                       mask[1] = 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 /* Rc */
+               }
+
+       case 58: /* logical $andcon,[s],a */
+               v := regoff(ctxt, &p.From)
+
+               r := int(p.Reg)
+               if r == 0 {
+                       r = int(p.To.Reg)
+               }
+               o1 = LOP_IRR(uint32(opirr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(v))
+
+       case 59: /* or/and $ucon,,r */
+               v := regoff(ctxt, &p.From)
+
+               r := int(p.Reg)
+               if r == 0 {
+                       r = int(p.To.Reg)
+               }
+               o1 = LOP_IRR(uint32(opirr(ctxt, int(p.As)+ALAST)), uint32(p.To.Reg), uint32(r), uint32(v)>>16) /* oris, xoris, andis */
+
+       case 60: /* tw to,a,b */
+               r := int(regoff(ctxt, &p.From) & 31)
+
+               o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(r), uint32(p.Reg), uint32(p.To.Reg))
+
+       case 61: /* tw to,a,$simm */
+               r := int(regoff(ctxt, &p.From) & 31)
+
+               v := regoff(ctxt, &p.To)
+               o1 = AOP_IRR(uint32(opirr(ctxt, int(p.As))), uint32(r), uint32(p.Reg), uint32(v))
+
+       case 62: /* rlwmi $sh,s,$mask,a */
+               v := regoff(ctxt, &p.From)
+
+               var mask [2]uint8
+               maskgen(ctxt, p, mask[:], uint32(regoff(ctxt, p.From3)))
+               o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.Reg), uint32(p.To.Reg), uint32(v))
+               o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
+
+       case 63: /* rlwmi b,s,$mask,a */
+               var mask [2]uint8
+               maskgen(ctxt, p, mask[:], uint32(regoff(ctxt, p.From3)))
+
+               o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.Reg), uint32(p.To.Reg), uint32(p.From.Reg))
+               o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
+
+       case 64: /* mtfsf fr[, $m] {,fpcsr} */
+               var v int32
+               if p.From3Type() != obj.TYPE_NONE {
+                       v = regoff(ctxt, p.From3) & 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 {
+                       ctxt.Diag("must specify FPSCR(n)\n%v", p)
+               }
+               o1 = OP_MTFSFI | (uint32(p.To.Reg)&15)<<23 | (uint32(regoff(ctxt, &p.From))&31)<<12
+
+       case 66: /* mov spr,r1; mov r1,spr, also dcr */
+               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)
+                       if REG_DCR0 <= v && v <= REG_DCR0+1023 {
+                               o1 = OPVCC(31, 451, 0, 0) /* mtdcr */
+                       } else {
+                               o1 = OPVCC(31, 467, 0, 0) /* mtspr */
+                       }
+               } else {
+                       r = int(p.To.Reg)
+                       v = int32(p.From.Reg)
+                       if REG_DCR0 <= v && v <= REG_DCR0+1023 {
+                               o1 = OPVCC(31, 323, 0, 0) /* mfdcr */
+                       } else {
+                               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.Type != obj.TYPE_REG || p.From.Reg < REG_CR0 || REG_CR7 < p.From.Reg || p.To.Type != obj.TYPE_REG || p.To.Reg < REG_CR0 || REG_CR7 < p.To.Reg {
+                       ctxt.Diag("illegal CR field number\n%v", p)
+               }
+               o1 = AOP_RRR(OP_MCRF, ((uint32(p.To.Reg) & 7) << 2), ((uint32(p.From.Reg) & 7) << 2), 0)
+
+       case 68: /* mfcr rD; mfocrf CRM,rD */
+               if p.From.Type == obj.TYPE_REG && REG_CR0 <= p.From.Reg && p.From.Reg <= REG_CR7 {
+                       v := int32(1 << uint(7-(p.To.Reg&7)))                                 /* CR(n) */
+                       o1 = AOP_RRR(OP_MFCR, uint32(p.To.Reg), 0, 0) | 1<<20 | uint32(v)<<12 /* new form, mfocrf */
+               } else {
+                       o1 = AOP_RRR(OP_MFCR, uint32(p.To.Reg), 0, 0) /* old form, whole register */
+               }
+
+       case 69: /* mtcrf CRM,rS */
+               var v int32
+               if p.From3Type() != obj.TYPE_NONE {
+                       if p.To.Reg != 0 {
+                               ctxt.Diag("can't use both mask and CR(n)\n%v", p)
+                       }
+                       v = regoff(ctxt, p.From3) & 0xff
+               } else {
+                       if p.To.Reg == 0 {
+                               v = 0xff /* CR */
+                       } else {
+                               v = 1 << uint(7-(p.To.Reg&7)) /* CR(n) */
+                       }
+               }
+
+               o1 = AOP_RRR(OP_MTCRF, uint32(p.From.Reg), 0, 0) | uint32(v)<<12
+
+       case 70: /* [f]cmp r,r,cr*/
+               var r int
+               if p.Reg == 0 {
+                       r = 0
+               } else {
+                       r = (int(p.Reg) & 7) << 2
+               }
+               o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(r), uint32(p.From.Reg), uint32(p.To.Reg))
+
+       case 71: /* cmp[l] r,i,cr*/
+               var r int
+               if p.Reg == 0 {
+                       r = 0
+               } else {
+                       r = (int(p.Reg) & 7) << 2
+               }
+               o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(r), uint32(p.From.Reg), 0) | uint32(regoff(ctxt, &p.To))&0xffff
+
+       case 72: /* slbmte (Rb+Rs -> slb[Rb]) -> Rs, Rb */
+               o1 = AOP_RRR(uint32(oprrr(ctxt, int(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 {
+                       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 {
+                               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 {
+                       ctxt.Diag("illegal syscall: %v", p)
+                       o1 = 0x7fe00008 // trap always
+               }
+
+               o2 = uint32(oprrr(ctxt, int(p.As)))
+               o3 = AOP_RRR(uint32(oprrr(ctxt, 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 := regoff(ctxt, &p.To)
+
+               o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(high16adjusted(v)))
+               o2 = AOP_IRR(uint32(opstore(ctxt, int(p.As))), uint32(p.From.Reg), REGTMP, uint32(v))
+               addaddrreloc(ctxt, p.To.Sym, &o1, &o2)
+
+       //if(dlm) reloc(&p->to, p->pc, 1);
+
+       case 75:
+               v := regoff(ctxt, &p.From)
+               o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(high16adjusted(v)))
+               o2 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(v))
+               addaddrreloc(ctxt, p.From.Sym, &o1, &o2)
+
+       //if(dlm) reloc(&p->from, p->pc, 1);
+
+       case 76:
+               v := regoff(ctxt, &p.From)
+               o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(high16adjusted(v)))
+               o2 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(v))
+               addaddrreloc(ctxt, p.From.Sym, &o1, &o2)
+               o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
+
+               //if(dlm) reloc(&p->from, p->pc, 1);
+
+       }
+
+       out[0] = o1
+       out[1] = o2
+       out[2] = o3
+       out[3] = o4
+       out[4] = o5
+       return
+}
+
+func vregoff(ctxt *obj.Link, a *obj.Addr) int64 {
+       ctxt.Instoffset = 0
+       if a != nil {
+               aclass(ctxt, a)
+       }
+       return ctxt.Instoffset
+}
+
+func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
+       return int32(vregoff(ctxt, a))
+}
+
+func oprrr(ctxt *obj.Link, a int) int32 {
+       switch a {
+       case AADD:
+               return int32(OPVCC(31, 266, 0, 0))
+       case AADDCC:
+               return int32(OPVCC(31, 266, 0, 1))
+       case AADDV:
+               return int32(OPVCC(31, 266, 1, 0))
+       case AADDVCC:
+               return int32(OPVCC(31, 266, 1, 1))
+       case AADDC:
+               return int32(OPVCC(31, 10, 0, 0))
+       case AADDCCC:
+               return int32(OPVCC(31, 10, 0, 1))
+       case AADDCV:
+               return int32(OPVCC(31, 10, 1, 0))
+       case AADDCVCC:
+               return int32(OPVCC(31, 10, 1, 1))
+       case AADDE:
+               return int32(OPVCC(31, 138, 0, 0))
+       case AADDECC:
+               return int32(OPVCC(31, 138, 0, 1))
+       case AADDEV:
+               return int32(OPVCC(31, 138, 1, 0))
+       case AADDEVCC:
+               return int32(OPVCC(31, 138, 1, 1))
+       case AADDME:
+               return int32(OPVCC(31, 234, 0, 0))
+       case AADDMECC:
+               return int32(OPVCC(31, 234, 0, 1))
+       case AADDMEV:
+               return int32(OPVCC(31, 234, 1, 0))
+       case AADDMEVCC:
+               return int32(OPVCC(31, 234, 1, 1))
+       case AADDZE:
+               return int32(OPVCC(31, 202, 0, 0))
+       case AADDZECC:
+               return int32(OPVCC(31, 202, 0, 1))
+       case AADDZEV:
+               return int32(OPVCC(31, 202, 1, 0))
+       case AADDZEVCC:
+               return int32(OPVCC(31, 202, 1, 1))
+
+       case AAND:
+               return int32(OPVCC(31, 28, 0, 0))
+       case AANDCC:
+               return int32(OPVCC(31, 28, 0, 1))
+       case AANDN:
+               return int32(OPVCC(31, 60, 0, 0))
+       case AANDNCC:
+               return int32(OPVCC(31, 60, 0, 1))
+
+       case ACMP:
+               return int32(OPVCC(31, 0, 0, 0) | 1<<21) /* L=1 */
+       case ACMPU:
+               return int32(OPVCC(31, 32, 0, 0) | 1<<21)
+       case ACMPW:
+               return int32(OPVCC(31, 0, 0, 0)) /* L=0 */
+       case ACMPWU:
+               return int32(OPVCC(31, 32, 0, 0))
+
+       case ACNTLZW:
+               return int32(OPVCC(31, 26, 0, 0))
+       case ACNTLZWCC:
+               return int32(OPVCC(31, 26, 0, 1))
+       case ACNTLZD:
+               return int32(OPVCC(31, 58, 0, 0))
+       case ACNTLZDCC:
+               return int32(OPVCC(31, 58, 0, 1))
+
+       case ACRAND:
+               return int32(OPVCC(19, 257, 0, 0))
+       case ACRANDN:
+               return int32(OPVCC(19, 129, 0, 0))
+       case ACREQV:
+               return int32(OPVCC(19, 289, 0, 0))
+       case ACRNAND:
+               return int32(OPVCC(19, 225, 0, 0))
+       case ACRNOR:
+               return int32(OPVCC(19, 33, 0, 0))
+       case ACROR:
+               return int32(OPVCC(19, 449, 0, 0))
+       case ACRORN:
+               return int32(OPVCC(19, 417, 0, 0))
+       case ACRXOR:
+               return int32(OPVCC(19, 193, 0, 0))
+
+       case ADCBF:
+               return int32(OPVCC(31, 86, 0, 0))
+       case ADCBI:
+               return int32(OPVCC(31, 470, 0, 0))
+       case ADCBST:
+               return int32(OPVCC(31, 54, 0, 0))
+       case ADCBT:
+               return int32(OPVCC(31, 278, 0, 0))
+       case ADCBTST:
+               return int32(OPVCC(31, 246, 0, 0))
+       case ADCBZ:
+               return int32(OPVCC(31, 1014, 0, 0))
+
+       case AREM, ADIVW:
+               return int32(OPVCC(31, 491, 0, 0))
+
+       case AREMCC, ADIVWCC:
+               return int32(OPVCC(31, 491, 0, 1))
+
+       case AREMV, ADIVWV:
+               return int32(OPVCC(31, 491, 1, 0))
+
+       case AREMVCC, ADIVWVCC:
+               return int32(OPVCC(31, 491, 1, 1))
+
+       case AREMU, ADIVWU:
+               return int32(OPVCC(31, 459, 0, 0))
+
+       case AREMUCC, ADIVWUCC:
+               return int32(OPVCC(31, 459, 0, 1))
+
+       case AREMUV, ADIVWUV:
+               return int32(OPVCC(31, 459, 1, 0))
+
+       case AREMUVCC, ADIVWUVCC:
+               return int32(OPVCC(31, 459, 1, 1))
+
+       case AREMD, ADIVD:
+               return int32(OPVCC(31, 489, 0, 0))
+
+       case AREMDCC, ADIVDCC:
+               return int32(OPVCC(31, 489, 0, 1))
+
+       case AREMDV, ADIVDV:
+               return int32(OPVCC(31, 489, 1, 0))
+
+       case AREMDVCC, ADIVDVCC:
+               return int32(OPVCC(31, 489, 1, 1))
+
+       case AREMDU, ADIVDU:
+               return int32(OPVCC(31, 457, 0, 0))
+
+       case AREMDUCC, ADIVDUCC:
+               return int32(OPVCC(31, 457, 0, 1))
+
+       case AREMDUV, ADIVDUV:
+               return int32(OPVCC(31, 457, 1, 0))
+
+       case AREMDUVCC, ADIVDUVCC:
+               return int32(OPVCC(31, 457, 1, 1))
+
+       case AEIEIO:
+               return int32(OPVCC(31, 854, 0, 0))
+
+       case AEQV:
+               return int32(OPVCC(31, 284, 0, 0))
+       case AEQVCC:
+               return int32(OPVCC(31, 284, 0, 1))
+
+       case AEXTSB:
+               return int32(OPVCC(31, 954, 0, 0))
+       case AEXTSBCC:
+               return int32(OPVCC(31, 954, 0, 1))
+       case AEXTSH:
+               return int32(OPVCC(31, 922, 0, 0))
+       case AEXTSHCC:
+               return int32(OPVCC(31, 922, 0, 1))
+       case AEXTSW:
+               return int32(OPVCC(31, 986, 0, 0))
+       case AEXTSWCC:
+               return int32(OPVCC(31, 986, 0, 1))
+
+       case AFABS:
+               return int32(OPVCC(63, 264, 0, 0))
+       case AFABSCC:
+               return int32(OPVCC(63, 264, 0, 1))
+       case AFADD:
+               return int32(OPVCC(63, 21, 0, 0))
+       case AFADDCC:
+               return int32(OPVCC(63, 21, 0, 1))
+       case AFADDS:
+               return int32(OPVCC(59, 21, 0, 0))
+       case AFADDSCC:
+               return int32(OPVCC(59, 21, 0, 1))
+       case AFCMPO:
+               return int32(OPVCC(63, 32, 0, 0))
+       case AFCMPU:
+               return int32(OPVCC(63, 0, 0, 0))
+       case AFCFID:
+               return int32(OPVCC(63, 846, 0, 0))
+       case AFCFIDCC:
+               return int32(OPVCC(63, 846, 0, 1))
+       case AFCTIW:
+               return int32(OPVCC(63, 14, 0, 0))
+       case AFCTIWCC:
+               return int32(OPVCC(63, 14, 0, 1))
+       case AFCTIWZ:
+               return int32(OPVCC(63, 15, 0, 0))
+       case AFCTIWZCC:
+               return int32(OPVCC(63, 15, 0, 1))
+       case AFCTID:
+               return int32(OPVCC(63, 814, 0, 0))
+       case AFCTIDCC:
+               return int32(OPVCC(63, 814, 0, 1))
+       case AFCTIDZ:
+               return int32(OPVCC(63, 815, 0, 0))
+       case AFCTIDZCC:
+               return int32(OPVCC(63, 815, 0, 1))
+       case AFDIV:
+               return int32(OPVCC(63, 18, 0, 0))
+       case AFDIVCC:
+               return int32(OPVCC(63, 18, 0, 1))
+       case AFDIVS:
+               return int32(OPVCC(59, 18, 0, 0))
+       case AFDIVSCC:
+               return int32(OPVCC(59, 18, 0, 1))
+       case AFMADD:
+               return int32(OPVCC(63, 29, 0, 0))
+       case AFMADDCC:
+               return int32(OPVCC(63, 29, 0, 1))
+       case AFMADDS:
+               return int32(OPVCC(59, 29, 0, 0))
+       case AFMADDSCC:
+               return int32(OPVCC(59, 29, 0, 1))
+
+       case AFMOVS, AFMOVD:
+               return int32(OPVCC(63, 72, 0, 0)) /* load */
+       case AFMOVDCC:
+               return int32(OPVCC(63, 72, 0, 1))
+       case AFMSUB:
+               return int32(OPVCC(63, 28, 0, 0))
+       case AFMSUBCC:
+               return int32(OPVCC(63, 28, 0, 1))
+       case AFMSUBS:
+               return int32(OPVCC(59, 28, 0, 0))
+       case AFMSUBSCC:
+               return int32(OPVCC(59, 28, 0, 1))
+       case AFMUL:
+               return int32(OPVCC(63, 25, 0, 0))
+       case AFMULCC:
+               return int32(OPVCC(63, 25, 0, 1))
+       case AFMULS:
+               return int32(OPVCC(59, 25, 0, 0))
+       case AFMULSCC:
+               return int32(OPVCC(59, 25, 0, 1))
+       case AFNABS:
+               return int32(OPVCC(63, 136, 0, 0))
+       case AFNABSCC:
+               return int32(OPVCC(63, 136, 0, 1))
+       case AFNEG:
+               return int32(OPVCC(63, 40, 0, 0))
+       case AFNEGCC:
+               return int32(OPVCC(63, 40, 0, 1))
+       case AFNMADD:
+               return int32(OPVCC(63, 31, 0, 0))
+       case AFNMADDCC:
+               return int32(OPVCC(63, 31, 0, 1))
+       case AFNMADDS:
+               return int32(OPVCC(59, 31, 0, 0))
+       case AFNMADDSCC:
+               return int32(OPVCC(59, 31, 0, 1))
+       case AFNMSUB:
+               return int32(OPVCC(63, 30, 0, 0))
+       case AFNMSUBCC:
+               return int32(OPVCC(63, 30, 0, 1))
+       case AFNMSUBS:
+               return int32(OPVCC(59, 30, 0, 0))
+       case AFNMSUBSCC:
+               return int32(OPVCC(59, 30, 0, 1))
+       case AFRES:
+               return int32(OPVCC(59, 24, 0, 0))
+       case AFRESCC:
+               return int32(OPVCC(59, 24, 0, 1))
+       case AFRSP:
+               return int32(OPVCC(63, 12, 0, 0))
+       case AFRSPCC:
+               return int32(OPVCC(63, 12, 0, 1))
+       case AFRSQRTE:
+               return int32(OPVCC(63, 26, 0, 0))
+       case AFRSQRTECC:
+               return int32(OPVCC(63, 26, 0, 1))
+       case AFSEL:
+               return int32(OPVCC(63, 23, 0, 0))
+       case AFSELCC:
+               return int32(OPVCC(63, 23, 0, 1))
+       case AFSQRT:
+               return int32(OPVCC(63, 22, 0, 0))
+       case AFSQRTCC:
+               return int32(OPVCC(63, 22, 0, 1))
+       case AFSQRTS:
+               return int32(OPVCC(59, 22, 0, 0))
+       case AFSQRTSCC:
+               return int32(OPVCC(59, 22, 0, 1))
+       case AFSUB:
+               return int32(OPVCC(63, 20, 0, 0))
+       case AFSUBCC:
+               return int32(OPVCC(63, 20, 0, 1))
+       case AFSUBS:
+               return int32(OPVCC(59, 20, 0, 0))
+       case AFSUBSCC:
+               return int32(OPVCC(59, 20, 0, 1))
+
+       case AICBI:
+               return int32(OPVCC(31, 982, 0, 0))
+       case AISYNC:
+               return int32(OPVCC(19, 150, 0, 0))
+
+       case AMTFSB0:
+               return int32(OPVCC(63, 70, 0, 0))
+       case AMTFSB0CC:
+               return int32(OPVCC(63, 70, 0, 1))
+       case AMTFSB1:
+               return int32(OPVCC(63, 38, 0, 0))
+       case AMTFSB1CC:
+               return int32(OPVCC(63, 38, 0, 1))
+
+       case AMULHW:
+               return int32(OPVCC(31, 75, 0, 0))
+       case AMULHWCC:
+               return int32(OPVCC(31, 75, 0, 1))
+       case AMULHWU:
+               return int32(OPVCC(31, 11, 0, 0))
+       case AMULHWUCC:
+               return int32(OPVCC(31, 11, 0, 1))
+       case AMULLW:
+               return int32(OPVCC(31, 235, 0, 0))
+       case AMULLWCC:
+               return int32(OPVCC(31, 235, 0, 1))
+       case AMULLWV:
+               return int32(OPVCC(31, 235, 1, 0))
+       case AMULLWVCC:
+               return int32(OPVCC(31, 235, 1, 1))
+
+       case AMULHD:
+               return int32(OPVCC(31, 73, 0, 0))
+       case AMULHDCC:
+               return int32(OPVCC(31, 73, 0, 1))
+       case AMULHDU:
+               return int32(OPVCC(31, 9, 0, 0))
+       case AMULHDUCC:
+               return int32(OPVCC(31, 9, 0, 1))
+       case AMULLD:
+               return int32(OPVCC(31, 233, 0, 0))
+       case AMULLDCC:
+               return int32(OPVCC(31, 233, 0, 1))
+       case AMULLDV:
+               return int32(OPVCC(31, 233, 1, 0))
+       case AMULLDVCC:
+               return int32(OPVCC(31, 233, 1, 1))
+
+       case ANAND:
+               return int32(OPVCC(31, 476, 0, 0))
+       case ANANDCC:
+               return int32(OPVCC(31, 476, 0, 1))
+       case ANEG:
+               return int32(OPVCC(31, 104, 0, 0))
+       case ANEGCC:
+               return int32(OPVCC(31, 104, 0, 1))
+       case ANEGV:
+               return int32(OPVCC(31, 104, 1, 0))
+       case ANEGVCC:
+               return int32(OPVCC(31, 104, 1, 1))
+       case ANOR:
+               return int32(OPVCC(31, 124, 0, 0))
+       case ANORCC:
+               return int32(OPVCC(31, 124, 0, 1))
+       case AOR:
+               return int32(OPVCC(31, 444, 0, 0))
+       case AORCC:
+               return int32(OPVCC(31, 444, 0, 1))
+       case AORN:
+               return int32(OPVCC(31, 412, 0, 0))
+       case AORNCC:
+               return int32(OPVCC(31, 412, 0, 1))
+
+       case ARFI:
+               return int32(OPVCC(19, 50, 0, 0))
+       case ARFCI:
+               return int32(OPVCC(19, 51, 0, 0))
+       case ARFID:
+               return int32(OPVCC(19, 18, 0, 0))
+       case AHRFID:
+               return int32(OPVCC(19, 274, 0, 0))
+
+       case ARLWMI:
+               return int32(OPVCC(20, 0, 0, 0))
+       case ARLWMICC:
+               return int32(OPVCC(20, 0, 0, 1))
+       case ARLWNM:
+               return int32(OPVCC(23, 0, 0, 0))
+       case ARLWNMCC:
+               return int32(OPVCC(23, 0, 0, 1))
+
+       case ARLDCL:
+               return int32(OPVCC(30, 8, 0, 0))
+       case ARLDCR:
+               return int32(OPVCC(30, 9, 0, 0))
+
+       case ASYSCALL:
+               return int32(OPVCC(17, 1, 0, 0))
+
+       case ASLW:
+               return int32(OPVCC(31, 24, 0, 0))
+       case ASLWCC:
+               return int32(OPVCC(31, 24, 0, 1))
+       case ASLD:
+               return int32(OPVCC(31, 27, 0, 0))
+       case ASLDCC:
+               return int32(OPVCC(31, 27, 0, 1))
+
+       case ASRAW:
+               return int32(OPVCC(31, 792, 0, 0))
+       case ASRAWCC:
+               return int32(OPVCC(31, 792, 0, 1))
+       case ASRAD:
+               return int32(OPVCC(31, 794, 0, 0))
+       case ASRADCC:
+               return int32(OPVCC(31, 794, 0, 1))
+
+       case ASRW:
+               return int32(OPVCC(31, 536, 0, 0))
+       case ASRWCC:
+               return int32(OPVCC(31, 536, 0, 1))
+       case ASRD:
+               return int32(OPVCC(31, 539, 0, 0))
+       case ASRDCC:
+               return int32(OPVCC(31, 539, 0, 1))
+
+       case ASUB:
+               return int32(OPVCC(31, 40, 0, 0))
+       case ASUBCC:
+               return int32(OPVCC(31, 40, 0, 1))
+       case ASUBV:
+               return int32(OPVCC(31, 40, 1, 0))
+       case ASUBVCC:
+               return int32(OPVCC(31, 40, 1, 1))
+       case ASUBC:
+               return int32(OPVCC(31, 8, 0, 0))
+       case ASUBCCC:
+               return int32(OPVCC(31, 8, 0, 1))
+       case ASUBCV:
+               return int32(OPVCC(31, 8, 1, 0))
+       case ASUBCVCC:
+               return int32(OPVCC(31, 8, 1, 1))
+       case ASUBE:
+               return int32(OPVCC(31, 136, 0, 0))
+       case ASUBECC:
+               return int32(OPVCC(31, 136, 0, 1))
+       case ASUBEV:
+               return int32(OPVCC(31, 136, 1, 0))
+       case ASUBEVCC:
+               return int32(OPVCC(31, 136, 1, 1))
+       case ASUBME:
+               return int32(OPVCC(31, 232, 0, 0))
+       case ASUBMECC:
+               return int32(OPVCC(31, 232, 0, 1))
+       case ASUBMEV:
+               return int32(OPVCC(31, 232, 1, 0))
+       case ASUBMEVCC:
+               return int32(OPVCC(31, 232, 1, 1))
+       case ASUBZE:
+               return int32(OPVCC(31, 200, 0, 0))
+       case ASUBZECC:
+               return int32(OPVCC(31, 200, 0, 1))
+       case ASUBZEV:
+               return int32(OPVCC(31, 200, 1, 0))
+       case ASUBZEVCC:
+               return int32(OPVCC(31, 200, 1, 1))
+
+       case ASYNC:
+               return int32(OPVCC(31, 598, 0, 0))
+       case APTESYNC:
+               return int32(OPVCC(31, 598, 0, 0) | 2<<21)
+
+       case ATLBIE:
+               return int32(OPVCC(31, 306, 0, 0))
+       case ATLBIEL:
+               return int32(OPVCC(31, 274, 0, 0))
+       case ATLBSYNC:
+               return int32(OPVCC(31, 566, 0, 0))
+       case ASLBIA:
+               return int32(OPVCC(31, 498, 0, 0))
+       case ASLBIE:
+               return int32(OPVCC(31, 434, 0, 0))
+       case ASLBMFEE:
+               return int32(OPVCC(31, 915, 0, 0))
+       case ASLBMFEV:
+               return int32(OPVCC(31, 851, 0, 0))
+       case ASLBMTE:
+               return int32(OPVCC(31, 402, 0, 0))
+
+       case ATW:
+               return int32(OPVCC(31, 4, 0, 0))
+       case ATD:
+               return int32(OPVCC(31, 68, 0, 0))
+
+       case AXOR:
+               return int32(OPVCC(31, 316, 0, 0))
+       case AXORCC:
+               return int32(OPVCC(31, 316, 0, 1))
+       }
+
+       ctxt.Diag("bad r/r opcode %v", obj.Aconv(a))
+       return 0
+}
+
+func opirr(ctxt *obj.Link, a int) int32 {
+       switch a {
+       case AADD:
+               return int32(OPVCC(14, 0, 0, 0))
+       case AADDC:
+               return int32(OPVCC(12, 0, 0, 0))
+       case AADDCCC:
+               return int32(OPVCC(13, 0, 0, 0))
+       case AADD + ALAST:
+               return int32(OPVCC(15, 0, 0, 0)) /* ADDIS/CAU */
+
+       case AANDCC:
+               return int32(OPVCC(28, 0, 0, 0))
+       case AANDCC + ALAST:
+               return int32(OPVCC(29, 0, 0, 0)) /* ANDIS./ANDIU. */
+
+       case ABR:
+               return int32(OPVCC(18, 0, 0, 0))
+       case ABL:
+               return int32(OPVCC(18, 0, 0, 0) | 1)
+       case obj.ADUFFZERO:
+               return int32(OPVCC(18, 0, 0, 0) | 1)
+       case obj.ADUFFCOPY:
+               return int32(OPVCC(18, 0, 0, 0) | 1)
+       case ABC:
+               return int32(OPVCC(16, 0, 0, 0))
+       case ABCL:
+               return int32(OPVCC(16, 0, 0, 0) | 1)
+
+       case ABEQ:
+               return int32(AOP_RRR(16<<26, 12, 2, 0))
+       case ABGE:
+               return int32(AOP_RRR(16<<26, 4, 0, 0))
+       case ABGT:
+               return int32(AOP_RRR(16<<26, 12, 1, 0))
+       case ABLE:
+               return int32(AOP_RRR(16<<26, 4, 1, 0))
+       case ABLT:
+               return int32(AOP_RRR(16<<26, 12, 0, 0))
+       case ABNE:
+               return int32(AOP_RRR(16<<26, 4, 2, 0))
+       case ABVC:
+               return int32(AOP_RRR(16<<26, 4, 3, 0))
+       case ABVS:
+               return int32(AOP_RRR(16<<26, 12, 3, 0))
+
+       case ACMP:
+               return int32(OPVCC(11, 0, 0, 0) | 1<<21) /* L=1 */
+       case ACMPU:
+               return int32(OPVCC(10, 0, 0, 0) | 1<<21)
+       case ACMPW:
+               return int32(OPVCC(11, 0, 0, 0)) /* L=0 */
+       case ACMPWU:
+               return int32(OPVCC(10, 0, 0, 0))
+       case ALSW:
+               return int32(OPVCC(31, 597, 0, 0))
+
+       case AMULLW:
+               return int32(OPVCC(7, 0, 0, 0))
+
+       case AOR:
+               return int32(OPVCC(24, 0, 0, 0))
+       case AOR + ALAST:
+               return int32(OPVCC(25, 0, 0, 0)) /* ORIS/ORIU */
+
+       case ARLWMI:
+               return int32(OPVCC(20, 0, 0, 0)) /* rlwimi */
+       case ARLWMICC:
+               return int32(OPVCC(20, 0, 0, 1))
+       case ARLDMI:
+               return int32(OPVCC(30, 0, 0, 0) | 3<<2) /* rldimi */
+       case ARLDMICC:
+               return int32(OPVCC(30, 0, 0, 1) | 3<<2)
+
+       case ARLWNM:
+               return int32(OPVCC(21, 0, 0, 0)) /* rlwinm */
+       case ARLWNMCC:
+               return int32(OPVCC(21, 0, 0, 1))
+
+       case ARLDCL:
+               return int32(OPVCC(30, 0, 0, 0)) /* rldicl */
+       case ARLDCLCC:
+               return int32(OPVCC(30, 0, 0, 1))
+       case ARLDCR:
+               return int32(OPVCC(30, 1, 0, 0)) /* rldicr */
+       case ARLDCRCC:
+               return int32(OPVCC(30, 1, 0, 1))
+       case ARLDC:
+               return int32(OPVCC(30, 0, 0, 0) | 2<<2)
+       case ARLDCCC:
+               return int32(OPVCC(30, 0, 0, 1) | 2<<2)
+
+       case ASRAW:
+               return int32(OPVCC(31, 824, 0, 0))
+       case ASRAWCC:
+               return int32(OPVCC(31, 824, 0, 1))
+       case ASRAD:
+               return int32(OPVCC(31, (413 << 1), 0, 0))
+       case ASRADCC:
+               return int32(OPVCC(31, (413 << 1), 0, 1))
+
+       case ASTSW:
+               return int32(OPVCC(31, 725, 0, 0))
+
+       case ASUBC:
+               return int32(OPVCC(8, 0, 0, 0))
+
+       case ATW:
+               return int32(OPVCC(3, 0, 0, 0))
+       case ATD:
+               return int32(OPVCC(2, 0, 0, 0))
+
+       case AXOR:
+               return int32(OPVCC(26, 0, 0, 0)) /* XORIL */
+       case AXOR + ALAST:
+               return int32(OPVCC(27, 0, 0, 0)) /* XORIU */
+       }
+
+       ctxt.Diag("bad opcode i/r %v", obj.Aconv(a))
+       return 0
+}
+
+/*
+ * load o(a),d
+ */
+func opload(ctxt *obj.Link, a int) int32 {
+       switch a {
+       case AMOVD:
+               return int32(OPVCC(58, 0, 0, 0)) /* ld */
+       case AMOVDU:
+               return int32(OPVCC(58, 0, 0, 1)) /* ldu */
+       case AMOVWZ:
+               return int32(OPVCC(32, 0, 0, 0)) /* lwz */
+       case AMOVWZU:
+               return int32(OPVCC(33, 0, 0, 0)) /* lwzu */
+       case AMOVW:
+               return int32(OPVCC(58, 0, 0, 0) | 1<<1) /* lwa */
+
+               /* no AMOVWU */
+       case AMOVB, AMOVBZ:
+               return int32(OPVCC(34, 0, 0, 0))
+               /* load */
+
+       case AMOVBU, AMOVBZU:
+               return int32(OPVCC(35, 0, 0, 0))
+       case AFMOVD:
+               return int32(OPVCC(50, 0, 0, 0))
+       case AFMOVDU:
+               return int32(OPVCC(51, 0, 0, 0))
+       case AFMOVS:
+               return int32(OPVCC(48, 0, 0, 0))
+       case AFMOVSU:
+               return int32(OPVCC(49, 0, 0, 0))
+       case AMOVH:
+               return int32(OPVCC(42, 0, 0, 0))
+       case AMOVHU:
+               return int32(OPVCC(43, 0, 0, 0))
+       case AMOVHZ:
+               return int32(OPVCC(40, 0, 0, 0))
+       case AMOVHZU:
+               return int32(OPVCC(41, 0, 0, 0))
+       case AMOVMW:
+               return int32(OPVCC(46, 0, 0, 0)) /* lmw */
+       }
+
+       ctxt.Diag("bad load opcode %v", obj.Aconv(a))
+       return 0
+}
+
+/*
+ * indexed load a(b),d
+ */
+func oploadx(ctxt *obj.Link, a int) int32 {
+       switch a {
+       case AMOVWZ:
+               return int32(OPVCC(31, 23, 0, 0)) /* lwzx */
+       case AMOVWZU:
+               return int32(OPVCC(31, 55, 0, 0)) /* lwzux */
+       case AMOVW:
+               return int32(OPVCC(31, 341, 0, 0)) /* lwax */
+       case AMOVWU:
+               return int32(OPVCC(31, 373, 0, 0)) /* lwaux */
+
+       case AMOVB, AMOVBZ:
+               return int32(OPVCC(31, 87, 0, 0)) /* lbzx */
+
+       case AMOVBU, AMOVBZU:
+               return int32(OPVCC(31, 119, 0, 0)) /* lbzux */
+       case AFMOVD:
+               return int32(OPVCC(31, 599, 0, 0)) /* lfdx */
+       case AFMOVDU:
+               return int32(OPVCC(31, 631, 0, 0)) /*  lfdux */
+       case AFMOVS:
+               return int32(OPVCC(31, 535, 0, 0)) /* lfsx */
+       case AFMOVSU:
+               return int32(OPVCC(31, 567, 0, 0)) /* lfsux */
+       case AMOVH:
+               return int32(OPVCC(31, 343, 0, 0)) /* lhax */
+       case AMOVHU:
+               return int32(OPVCC(31, 375, 0, 0)) /* lhaux */
+       case AMOVHBR:
+               return int32(OPVCC(31, 790, 0, 0)) /* lhbrx */
+       case AMOVWBR:
+               return int32(OPVCC(31, 534, 0, 0)) /* lwbrx */
+       case AMOVHZ:
+               return int32(OPVCC(31, 279, 0, 0)) /* lhzx */
+       case AMOVHZU:
+               return int32(OPVCC(31, 311, 0, 0)) /* lhzux */
+       case AECIWX:
+               return int32(OPVCC(31, 310, 0, 0)) /* eciwx */
+       case ALWAR:
+               return int32(OPVCC(31, 20, 0, 0)) /* lwarx */
+       case ALDAR:
+               return int32(OPVCC(31, 84, 0, 0))
+       case ALSW:
+               return int32(OPVCC(31, 533, 0, 0)) /* lswx */
+       case AMOVD:
+               return int32(OPVCC(31, 21, 0, 0)) /* ldx */
+       case AMOVDU:
+               return int32(OPVCC(31, 53, 0, 0)) /* ldux */
+       }
+
+       ctxt.Diag("bad loadx opcode %v", obj.Aconv(a))
+       return 0
+}
+
+/*
+ * store s,o(d)
+ */
+func opstore(ctxt *obj.Link, a int) int32 {
+       switch a {
+       case AMOVB, AMOVBZ:
+               return int32(OPVCC(38, 0, 0, 0)) /* stb */
+
+       case AMOVBU, AMOVBZU:
+               return int32(OPVCC(39, 0, 0, 0)) /* stbu */
+       case AFMOVD:
+               return int32(OPVCC(54, 0, 0, 0)) /* stfd */
+       case AFMOVDU:
+               return int32(OPVCC(55, 0, 0, 0)) /* stfdu */
+       case AFMOVS:
+               return int32(OPVCC(52, 0, 0, 0)) /* stfs */
+       case AFMOVSU:
+               return int32(OPVCC(53, 0, 0, 0)) /* stfsu */
+
+       case AMOVHZ, AMOVH:
+               return int32(OPVCC(44, 0, 0, 0)) /* sth */
+
+       case AMOVHZU, AMOVHU:
+               return int32(OPVCC(45, 0, 0, 0)) /* sthu */
+       case AMOVMW:
+               return int32(OPVCC(47, 0, 0, 0)) /* stmw */
+       case ASTSW:
+               return int32(OPVCC(31, 725, 0, 0)) /* stswi */
+
+       case AMOVWZ, AMOVW:
+               return int32(OPVCC(36, 0, 0, 0)) /* stw */
+
+       case AMOVWZU, AMOVWU:
+               return int32(OPVCC(37, 0, 0, 0)) /* stwu */
+       case AMOVD:
+               return int32(OPVCC(62, 0, 0, 0)) /* std */
+       case AMOVDU:
+               return int32(OPVCC(62, 0, 0, 1)) /* stdu */
+       }
+
+       ctxt.Diag("unknown store opcode %v", obj.Aconv(a))
+       return 0
+}
+
+/*
+ * indexed store s,a(b)
+ */
+func opstorex(ctxt *obj.Link, a int) int32 {
+       switch a {
+       case AMOVB, AMOVBZ:
+               return int32(OPVCC(31, 215, 0, 0)) /* stbx */
+
+       case AMOVBU, AMOVBZU:
+               return int32(OPVCC(31, 247, 0, 0)) /* stbux */
+       case AFMOVD:
+               return int32(OPVCC(31, 727, 0, 0)) /* stfdx */
+       case AFMOVDU:
+               return int32(OPVCC(31, 759, 0, 0)) /* stfdux */
+       case AFMOVS:
+               return int32(OPVCC(31, 663, 0, 0)) /* stfsx */
+       case AFMOVSU:
+               return int32(OPVCC(31, 695, 0, 0)) /* stfsux */
+
+       case AMOVHZ, AMOVH:
+               return int32(OPVCC(31, 407, 0, 0)) /* sthx */
+       case AMOVHBR:
+               return int32(OPVCC(31, 918, 0, 0)) /* sthbrx */
+
+       case AMOVHZU, AMOVHU:
+               return int32(OPVCC(31, 439, 0, 0)) /* sthux */
+
+       case AMOVWZ, AMOVW:
+               return int32(OPVCC(31, 151, 0, 0)) /* stwx */
+
+       case AMOVWZU, AMOVWU:
+               return int32(OPVCC(31, 183, 0, 0)) /* stwux */
+       case ASTSW:
+               return int32(OPVCC(31, 661, 0, 0)) /* stswx */
+       case AMOVWBR:
+               return int32(OPVCC(31, 662, 0, 0)) /* stwbrx */
+       case ASTWCCC:
+               return int32(OPVCC(31, 150, 0, 1)) /* stwcx. */
+       case ASTDCCC:
+               return int32(OPVCC(31, 214, 0, 1)) /* stwdx. */
+       case AECOWX:
+               return int32(OPVCC(31, 438, 0, 0)) /* ecowx */
+       case AMOVD:
+               return int32(OPVCC(31, 149, 0, 0)) /* stdx */
+       case AMOVDU:
+               return int32(OPVCC(31, 181, 0, 0)) /* stdux */
+       }
+
+       ctxt.Diag("unknown storex opcode %v", obj.Aconv(a))
+       return 0
+}
diff --git a/src/cmd/internal/obj/mips/list0.go b/src/cmd/internal/obj/mips/list0.go
new file mode 100644 (file)
index 0000000..4cdcfbc
--- /dev/null
@@ -0,0 +1,98 @@
+// cmd/9l/list.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"
+       "fmt"
+)
+
+func init() {
+       obj.RegisterRegister(obj.RBasePPC64, REG_DCR0+1024, Rconv)
+       obj.RegisterOpcode(obj.ABasePPC64, Anames)
+}
+
+func Rconv(r int) string {
+       if r == 0 {
+               return "NONE"
+       }
+       if r == REGG {
+               // Special case.
+               return "g"
+       }
+       if REG_R0 <= r && r <= REG_R31 {
+               return fmt.Sprintf("R%d", r-REG_R0)
+       }
+       if REG_F0 <= r && r <= REG_F31 {
+               return fmt.Sprintf("F%d", r-REG_F0)
+       }
+       if REG_CR0 <= r && r <= REG_CR7 {
+               return fmt.Sprintf("CR%d", r-REG_CR0)
+       }
+       if r == REG_CR {
+               return "CR"
+       }
+       if REG_SPR0 <= r && r <= REG_SPR0+1023 {
+               switch r {
+               case REG_XER:
+                       return "XER"
+
+               case REG_LR:
+                       return "LR"
+
+               case REG_CTR:
+                       return "CTR"
+               }
+
+               return fmt.Sprintf("SPR(%d)", r-REG_SPR0)
+       }
+
+       if REG_DCR0 <= r && r <= REG_DCR0+1023 {
+               return fmt.Sprintf("DCR(%d)", r-REG_DCR0)
+       }
+       if r == REG_FPSCR {
+               return "FPSCR"
+       }
+       if r == REG_MSR {
+               return "MSR"
+       }
+
+       return fmt.Sprintf("Rgok(%d)", r-obj.RBasePPC64)
+}
+
+func DRconv(a int) string {
+       s := "C_??"
+       if a >= C_NONE && a <= C_NCLASS {
+               s = cnames9[a]
+       }
+       var fp string
+       fp += s
+       return fp
+}
diff --git a/src/cmd/internal/obj/mips/obj0.go b/src/cmd/internal/obj/mips/obj0.go
new file mode 100644 (file)
index 0000000..1eddc6f
--- /dev/null
@@ -0,0 +1,968 @@
+// cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.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"
+       "encoding/binary"
+       "fmt"
+       "math"
+)
+
+func progedit(ctxt *obj.Link, p *obj.Prog) {
+       p.From.Class = 0
+       p.To.Class = 0
+
+       // Rewrite BR/BL to symbol as TYPE_BRANCH.
+       switch p.As {
+       case ABR,
+               ABL,
+               obj.ARET,
+               obj.ADUFFZERO,
+               obj.ADUFFCOPY:
+               if p.To.Sym != nil {
+                       p.To.Type = obj.TYPE_BRANCH
+               }
+       }
+
+       // Rewrite float constants to values stored in memory.
+       switch p.As {
+       case AFMOVS:
+               if p.From.Type == obj.TYPE_FCONST {
+                       f32 := float32(p.From.Val.(float64))
+                       i32 := math.Float32bits(f32)
+                       literal := fmt.Sprintf("$f32.%08x", i32)
+                       s := obj.Linklookup(ctxt, literal, 0)
+                       s.Size = 4
+                       p.From.Type = obj.TYPE_MEM
+                       p.From.Sym = s
+                       p.From.Name = obj.NAME_EXTERN
+                       p.From.Offset = 0
+               }
+
+       case AFMOVD:
+               if p.From.Type == obj.TYPE_FCONST {
+                       i64 := math.Float64bits(p.From.Val.(float64))
+                       literal := fmt.Sprintf("$f64.%016x", i64)
+                       s := obj.Linklookup(ctxt, literal, 0)
+                       s.Size = 8
+                       p.From.Type = obj.TYPE_MEM
+                       p.From.Sym = s
+                       p.From.Name = obj.NAME_EXTERN
+                       p.From.Offset = 0
+               }
+
+               // Put >32-bit constants in memory and load them
+       case AMOVD:
+               if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
+                       literal := fmt.Sprintf("$i64.%016x", uint64(p.From.Offset))
+                       s := obj.Linklookup(ctxt, literal, 0)
+                       s.Size = 8
+                       p.From.Type = obj.TYPE_MEM
+                       p.From.Sym = s
+                       p.From.Name = obj.NAME_EXTERN
+                       p.From.Offset = 0
+               }
+       }
+
+       // Rewrite SUB constants into ADD.
+       switch p.As {
+       case ASUBC:
+               if p.From.Type == obj.TYPE_CONST {
+                       p.From.Offset = -p.From.Offset
+                       p.As = AADDC
+               }
+
+       case ASUBCCC:
+               if p.From.Type == obj.TYPE_CONST {
+                       p.From.Offset = -p.From.Offset
+                       p.As = AADDCCC
+               }
+
+       case ASUB:
+               if p.From.Type == obj.TYPE_CONST {
+                       p.From.Offset = -p.From.Offset
+                       p.As = AADD
+               }
+       }
+}
+
+func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+       // TODO(minux): add morestack short-cuts with small fixed frame-size.
+       ctxt.Cursym = cursym
+
+       if cursym.Text == nil || cursym.Text.Link == nil {
+               return
+       }
+
+       p := cursym.Text
+       textstksiz := p.To.Offset
+
+       cursym.Args = p.To.Val.(int32)
+       cursym.Locals = int32(textstksiz)
+
+       /*
+        * find leaf subroutines
+        * strip NOPs
+        * expand RET
+        * expand BECOME pseudo
+        */
+       if ctxt.Debugvlog != 0 {
+               fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime())
+       }
+       ctxt.Bso.Flush()
+
+       var q *obj.Prog
+       var q1 *obj.Prog
+       for p := cursym.Text; p != nil; p = p.Link {
+               switch p.As {
+               /* too hard, just leave alone */
+               case obj.ATEXT:
+                       q = p
+
+                       p.Mark |= LABEL | LEAF | SYNC
+                       if p.Link != nil {
+                               p.Link.Mark |= LABEL
+                       }
+
+               case ANOR:
+                       q = p
+                       if p.To.Type == obj.TYPE_REG {
+                               if p.To.Reg == REGZERO {
+                                       p.Mark |= LABEL | SYNC
+                               }
+                       }
+
+               case ALWAR,
+                       ASTWCCC,
+                       AECIWX,
+                       AECOWX,
+                       AEIEIO,
+                       AICBI,
+                       AISYNC,
+                       ATLBIE,
+                       ATLBIEL,
+                       ASLBIA,
+                       ASLBIE,
+                       ASLBMFEE,
+                       ASLBMFEV,
+                       ASLBMTE,
+                       ADCBF,
+                       ADCBI,
+                       ADCBST,
+                       ADCBT,
+                       ADCBTST,
+                       ADCBZ,
+                       ASYNC,
+                       ATLBSYNC,
+                       APTESYNC,
+                       ATW,
+                       AWORD,
+                       ARFI,
+                       ARFCI,
+                       ARFID,
+                       AHRFID:
+                       q = p
+                       p.Mark |= LABEL | SYNC
+                       continue
+
+               case AMOVW, AMOVWZ, AMOVD:
+                       q = p
+                       if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL {
+                               p.Mark |= LABEL | SYNC
+                       }
+                       continue
+
+               case AFABS,
+                       AFABSCC,
+                       AFADD,
+                       AFADDCC,
+                       AFCTIW,
+                       AFCTIWCC,
+                       AFCTIWZ,
+                       AFCTIWZCC,
+                       AFDIV,
+                       AFDIVCC,
+                       AFMADD,
+                       AFMADDCC,
+                       AFMOVD,
+                       AFMOVDU,
+                       /* case AFMOVDS: */
+                       AFMOVS,
+                       AFMOVSU,
+
+                       /* case AFMOVSD: */
+                       AFMSUB,
+                       AFMSUBCC,
+                       AFMUL,
+                       AFMULCC,
+                       AFNABS,
+                       AFNABSCC,
+                       AFNEG,
+                       AFNEGCC,
+                       AFNMADD,
+                       AFNMADDCC,
+                       AFNMSUB,
+                       AFNMSUBCC,
+                       AFRSP,
+                       AFRSPCC,
+                       AFSUB,
+                       AFSUBCC:
+                       q = p
+
+                       p.Mark |= FLOAT
+                       continue
+
+               case ABL,
+                       ABCL,
+                       obj.ADUFFZERO,
+                       obj.ADUFFCOPY:
+                       cursym.Text.Mark &^= LEAF
+                       fallthrough
+
+               case ABC,
+                       ABEQ,
+                       ABGE,
+                       ABGT,
+                       ABLE,
+                       ABLT,
+                       ABNE,
+                       ABR,
+                       ABVC,
+                       ABVS:
+                       p.Mark |= BRANCH
+                       q = p
+                       q1 = p.Pcond
+                       if q1 != nil {
+                               for q1.As == obj.ANOP {
+                                       q1 = q1.Link
+                                       p.Pcond = q1
+                               }
+
+                               if q1.Mark&LEAF == 0 {
+                                       q1.Mark |= LABEL
+                               }
+                       } else {
+                               p.Mark |= LABEL
+                       }
+                       q1 = p.Link
+                       if q1 != nil {
+                               q1.Mark |= LABEL
+                       }
+                       continue
+
+               case AFCMPO, AFCMPU:
+                       q = p
+                       p.Mark |= FCMP | FLOAT
+                       continue
+
+               case obj.ARET:
+                       q = p
+                       if p.Link != nil {
+                               p.Link.Mark |= LABEL
+                       }
+                       continue
+
+               case obj.ANOP:
+                       q1 = p.Link
+                       q.Link = q1 /* q is non-nop */
+                       q1.Mark |= p.Mark
+                       continue
+
+               default:
+                       q = p
+                       continue
+               }
+       }
+
+       autosize := int32(0)
+       var aoffset int
+       var mov int
+       var o int
+       var p1 *obj.Prog
+       var p2 *obj.Prog
+       for p := cursym.Text; p != nil; p = p.Link {
+               o = int(p.As)
+               switch o {
+               case obj.ATEXT:
+                       mov = AMOVD
+                       aoffset = 0
+                       autosize = int32(textstksiz + 8)
+                       if (p.Mark&LEAF != 0) && autosize <= 8 {
+                               autosize = 0
+                       } else if autosize&4 != 0 {
+                               autosize += 4
+                       }
+                       p.To.Offset = int64(autosize) - 8
+
+                       if p.From3.Offset&obj.NOSPLIT == 0 {
+                               p = stacksplit(ctxt, p, autosize) // emit split check
+                       }
+
+                       q = p
+
+                       if autosize != 0 {
+                               /* use MOVDU to adjust R1 when saving R31, if autosize is small */
+                               if cursym.Text.Mark&LEAF == 0 && autosize >= -BIG && autosize <= BIG {
+                                       mov = AMOVDU
+                                       aoffset = int(-autosize)
+                               } else {
+                                       q = obj.Appendp(ctxt, p)
+                                       q.As = AADD
+                                       q.Lineno = p.Lineno
+                                       q.From.Type = obj.TYPE_CONST
+                                       q.From.Offset = int64(-autosize)
+                                       q.To.Type = obj.TYPE_REG
+                                       q.To.Reg = REGSP
+                                       q.Spadj = +autosize
+                               }
+                       } else if cursym.Text.Mark&LEAF == 0 {
+                               if ctxt.Debugvlog != 0 {
+                                       fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name)
+                                       ctxt.Bso.Flush()
+                               }
+
+                               cursym.Text.Mark |= LEAF
+                       }
+
+                       if cursym.Text.Mark&LEAF != 0 {
+                               cursym.Leaf = 1
+                               break
+                       }
+
+                       q = obj.Appendp(ctxt, q)
+                       q.As = AMOVD
+                       q.Lineno = p.Lineno
+                       q.From.Type = obj.TYPE_REG
+                       q.From.Reg = REG_LR
+                       q.To.Type = obj.TYPE_REG
+                       q.To.Reg = REGTMP
+
+                       q = obj.Appendp(ctxt, q)
+                       q.As = int16(mov)
+                       q.Lineno = p.Lineno
+                       q.From.Type = obj.TYPE_REG
+                       q.From.Reg = REGTMP
+                       q.To.Type = obj.TYPE_MEM
+                       q.To.Offset = int64(aoffset)
+                       q.To.Reg = REGSP
+                       if q.As == AMOVDU {
+                               q.Spadj = int32(-aoffset)
+                       }
+
+                       if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
+                               // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+                               //
+                               //      MOVD g_panic(g), R3
+                               //      CMP R0, R3
+                               //      BEQ end
+                               //      MOVD panic_argp(R3), R4
+                               //      ADD $(autosize+8), R1, R5
+                               //      CMP R4, R5
+                               //      BNE end
+                               //      ADD $8, R1, R6
+                               //      MOVD R6, panic_argp(R3)
+                               // end:
+                               //      NOP
+                               //
+                               // The NOP is needed to give the jumps somewhere to land.
+                               // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
+
+                               q = obj.Appendp(ctxt, q)
+
+                               q.As = AMOVD
+                               q.From.Type = obj.TYPE_MEM
+                               q.From.Reg = REGG
+                               q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+                               q.To.Type = obj.TYPE_REG
+                               q.To.Reg = REG_R3
+
+                               q = obj.Appendp(ctxt, q)
+                               q.As = ACMP
+                               q.From.Type = obj.TYPE_REG
+                               q.From.Reg = REG_R0
+                               q.To.Type = obj.TYPE_REG
+                               q.To.Reg = REG_R3
+
+                               q = obj.Appendp(ctxt, q)
+                               q.As = ABEQ
+                               q.To.Type = obj.TYPE_BRANCH
+                               p1 = q
+
+                               q = obj.Appendp(ctxt, q)
+                               q.As = AMOVD
+                               q.From.Type = obj.TYPE_MEM
+                               q.From.Reg = REG_R3
+                               q.From.Offset = 0 // Panic.argp
+                               q.To.Type = obj.TYPE_REG
+                               q.To.Reg = REG_R4
+
+                               q = obj.Appendp(ctxt, q)
+                               q.As = AADD
+                               q.From.Type = obj.TYPE_CONST
+                               q.From.Offset = int64(autosize) + 8
+                               q.Reg = REGSP
+                               q.To.Type = obj.TYPE_REG
+                               q.To.Reg = REG_R5
+
+                               q = obj.Appendp(ctxt, q)
+                               q.As = ACMP
+                               q.From.Type = obj.TYPE_REG
+                               q.From.Reg = REG_R4
+                               q.To.Type = obj.TYPE_REG
+                               q.To.Reg = REG_R5
+
+                               q = obj.Appendp(ctxt, q)
+                               q.As = ABNE
+                               q.To.Type = obj.TYPE_BRANCH
+                               p2 = q
+
+                               q = obj.Appendp(ctxt, q)
+                               q.As = AADD
+                               q.From.Type = obj.TYPE_CONST
+                               q.From.Offset = 8
+                               q.Reg = REGSP
+                               q.To.Type = obj.TYPE_REG
+                               q.To.Reg = REG_R6
+
+                               q = obj.Appendp(ctxt, q)
+                               q.As = AMOVD
+                               q.From.Type = obj.TYPE_REG
+                               q.From.Reg = REG_R6
+                               q.To.Type = obj.TYPE_MEM
+                               q.To.Reg = REG_R3
+                               q.To.Offset = 0 // Panic.argp
+
+                               q = obj.Appendp(ctxt, q)
+
+                               q.As = obj.ANOP
+                               p1.Pcond = q
+                               p2.Pcond = q
+                       }
+
+               case obj.ARET:
+                       if p.From.Type == obj.TYPE_CONST {
+                               ctxt.Diag("using BECOME (%v) is not supported!", p)
+                               break
+                       }
+
+                       if p.To.Sym != nil { // retjmp
+                               p.As = ABR
+                               p.To.Type = obj.TYPE_BRANCH
+                               break
+                       }
+
+                       if cursym.Text.Mark&LEAF != 0 {
+                               if autosize == 0 {
+                                       p.As = ABR
+                                       p.From = obj.Addr{}
+                                       p.To.Type = obj.TYPE_REG
+                                       p.To.Reg = REG_LR
+                                       p.Mark |= BRANCH
+                                       break
+                               }
+
+                               p.As = AADD
+                               p.From.Type = obj.TYPE_CONST
+                               p.From.Offset = int64(autosize)
+                               p.To.Type = obj.TYPE_REG
+                               p.To.Reg = REGSP
+                               p.Spadj = -autosize
+
+                               q = ctxt.NewProg()
+                               q.As = ABR
+                               q.Lineno = p.Lineno
+                               q.To.Type = obj.TYPE_REG
+                               q.To.Reg = REG_LR
+                               q.Mark |= BRANCH
+                               q.Spadj = +autosize
+
+                               q.Link = p.Link
+                               p.Link = q
+                               break
+                       }
+
+                       p.As = AMOVD
+                       p.From.Type = obj.TYPE_MEM
+                       p.From.Offset = 0
+                       p.From.Reg = REGSP
+                       p.To.Type = obj.TYPE_REG
+                       p.To.Reg = REGTMP
+
+                       q = ctxt.NewProg()
+                       q.As = AMOVD
+                       q.Lineno = p.Lineno
+                       q.From.Type = obj.TYPE_REG
+                       q.From.Reg = REGTMP
+                       q.To.Type = obj.TYPE_REG
+                       q.To.Reg = REG_LR
+
+                       q.Link = p.Link
+                       p.Link = q
+                       p = q
+
+                       if false {
+                               // Debug bad returns
+                               q = ctxt.NewProg()
+
+                               q.As = AMOVD
+                               q.Lineno = p.Lineno
+                               q.From.Type = obj.TYPE_MEM
+                               q.From.Offset = 0
+                               q.From.Reg = REGTMP
+                               q.To.Type = obj.TYPE_REG
+                               q.To.Reg = REGTMP
+
+                               q.Link = p.Link
+                               p.Link = q
+                               p = q
+                       }
+
+                       if autosize != 0 {
+                               q = ctxt.NewProg()
+                               q.As = AADD
+                               q.Lineno = p.Lineno
+                               q.From.Type = obj.TYPE_CONST
+                               q.From.Offset = int64(autosize)
+                               q.To.Type = obj.TYPE_REG
+                               q.To.Reg = REGSP
+                               q.Spadj = -autosize
+
+                               q.Link = p.Link
+                               p.Link = q
+                       }
+
+                       q1 = ctxt.NewProg()
+                       q1.As = ABR
+                       q1.Lineno = p.Lineno
+                       q1.To.Type = obj.TYPE_REG
+                       q1.To.Reg = REG_LR
+                       q1.Mark |= BRANCH
+                       q1.Spadj = +autosize
+
+                       q1.Link = q.Link
+                       q.Link = q1
+
+               case AADD:
+                       if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
+                               p.Spadj = int32(-p.From.Offset)
+                       }
+               }
+       }
+}
+
+/*
+// instruction scheduling
+       if(debug['Q'] == 0)
+               return;
+
+       curtext = nil;
+       q = nil;        // p - 1
+       q1 = firstp;    // top of block
+       o = 0;          // count of instructions
+       for(p = firstp; p != nil; p = p1) {
+               p1 = p->link;
+               o++;
+               if(p->mark & NOSCHED){
+                       if(q1 != p){
+                               sched(q1, q);
+                       }
+                       for(; p != nil; p = p->link){
+                               if(!(p->mark & NOSCHED))
+                                       break;
+                               q = p;
+                       }
+                       p1 = p;
+                       q1 = p;
+                       o = 0;
+                       continue;
+               }
+               if(p->mark & (LABEL|SYNC)) {
+                       if(q1 != p)
+                               sched(q1, q);
+                       q1 = p;
+                       o = 1;
+               }
+               if(p->mark & (BRANCH|SYNC)) {
+                       sched(q1, p);
+                       q1 = p1;
+                       o = 0;
+               }
+               if(o >= NSCHED) {
+                       sched(q1, p);
+                       q1 = p1;
+                       o = 0;
+               }
+               q = p;
+       }
+*/
+func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
+       // MOVD g_stackguard(g), R3
+       p = obj.Appendp(ctxt, p)
+
+       p.As = AMOVD
+       p.From.Type = obj.TYPE_MEM
+       p.From.Reg = REGG
+       p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+       if ctxt.Cursym.Cfunc != 0 {
+               p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+       }
+       p.To.Type = obj.TYPE_REG
+       p.To.Reg = REG_R3
+
+       var q *obj.Prog
+       if framesize <= obj.StackSmall {
+               // small stack: SP < stackguard
+               //      CMP     stackguard, SP
+               p = obj.Appendp(ctxt, p)
+
+               p.As = ACMPU
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REG_R3
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGSP
+       } else if framesize <= obj.StackBig {
+               // large stack: SP-framesize < stackguard-StackSmall
+               //      ADD $-framesize, SP, R4
+               //      CMP stackguard, R4
+               p = obj.Appendp(ctxt, p)
+
+               p.As = AADD
+               p.From.Type = obj.TYPE_CONST
+               p.From.Offset = int64(-framesize)
+               p.Reg = REGSP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REG_R4
+
+               p = obj.Appendp(ctxt, p)
+               p.As = ACMPU
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REG_R3
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REG_R4
+       } else {
+               // Such a large stack we need to protect against wraparound.
+               // If SP is close to zero:
+               //      SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
+               // The +StackGuard on both sides is required to keep the left side positive:
+               // SP is allowed to be slightly below stackguard. See stack.h.
+               //
+               // Preemption sets stackguard to StackPreempt, a very large value.
+               // That breaks the math above, so we have to check for that explicitly.
+               //      // stackguard is R3
+               //      CMP     R3, $StackPreempt
+               //      BEQ     label-of-call-to-morestack
+               //      ADD     $StackGuard, SP, R4
+               //      SUB     R3, R4
+               //      MOVD    $(framesize+(StackGuard-StackSmall)), R31
+               //      CMPU    R31, R4
+               p = obj.Appendp(ctxt, p)
+
+               p.As = ACMP
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REG_R3
+               p.To.Type = obj.TYPE_CONST
+               p.To.Offset = obj.StackPreempt
+
+               p = obj.Appendp(ctxt, p)
+               q = p
+               p.As = ABEQ
+               p.To.Type = obj.TYPE_BRANCH
+
+               p = obj.Appendp(ctxt, p)
+               p.As = AADD
+               p.From.Type = obj.TYPE_CONST
+               p.From.Offset = obj.StackGuard
+               p.Reg = REGSP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REG_R4
+
+               p = obj.Appendp(ctxt, p)
+               p.As = ASUB
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REG_R3
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REG_R4
+
+               p = obj.Appendp(ctxt, p)
+               p.As = AMOVD
+               p.From.Type = obj.TYPE_CONST
+               p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REGTMP
+
+               p = obj.Appendp(ctxt, p)
+               p.As = ACMPU
+               p.From.Type = obj.TYPE_REG
+               p.From.Reg = REGTMP
+               p.To.Type = obj.TYPE_REG
+               p.To.Reg = REG_R4
+       }
+
+       // q1: BLT      done
+       p = obj.Appendp(ctxt, p)
+       q1 := p
+
+       p.As = ABLT
+       p.To.Type = obj.TYPE_BRANCH
+
+       // MOVD LR, R5
+       p = obj.Appendp(ctxt, p)
+
+       p.As = AMOVD
+       p.From.Type = obj.TYPE_REG
+       p.From.Reg = REG_LR
+       p.To.Type = obj.TYPE_REG
+       p.To.Reg = REG_R5
+       if q != nil {
+               q.Pcond = p
+       }
+
+       // BL   runtime.morestack(SB)
+       p = obj.Appendp(ctxt, p)
+
+       p.As = ABL
+       p.To.Type = obj.TYPE_BRANCH
+       if ctxt.Cursym.Cfunc != 0 {
+               p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
+       } else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 {
+               p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
+       } else {
+               p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
+       }
+
+       // BR   start
+       p = obj.Appendp(ctxt, p)
+
+       p.As = ABR
+       p.To.Type = obj.TYPE_BRANCH
+       p.Pcond = ctxt.Cursym.Text.Link
+
+       // placeholder for q1's jump target
+       p = obj.Appendp(ctxt, p)
+
+       p.As = obj.ANOP // zero-width place holder
+       q1.Pcond = p
+
+       return p
+}
+
+func follow(ctxt *obj.Link, s *obj.LSym) {
+       ctxt.Cursym = s
+
+       firstp := ctxt.NewProg()
+       lastp := firstp
+       xfol(ctxt, s.Text, &lastp)
+       lastp.Link = nil
+       s.Text = firstp.Link
+}
+
+func relinv(a int) int {
+       switch a {
+       case ABEQ:
+               return ABNE
+       case ABNE:
+               return ABEQ
+
+       case ABGE:
+               return ABLT
+       case ABLT:
+               return ABGE
+
+       case ABGT:
+               return ABLE
+       case ABLE:
+               return ABGT
+
+       case ABVC:
+               return ABVS
+       case ABVS:
+               return ABVC
+       }
+
+       return 0
+}
+
+func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) {
+       var q *obj.Prog
+       var r *obj.Prog
+       var a int
+       var b int
+       var i int
+
+loop:
+       if p == nil {
+               return
+       }
+       a = int(p.As)
+       if a == ABR {
+               q = p.Pcond
+               if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) {
+                       p.Mark |= FOLL
+                       (*last).Link = p
+                       *last = p
+                       p = p.Link
+                       xfol(ctxt, p, last)
+                       p = q
+                       if p != nil && p.Mark&FOLL == 0 {
+                               goto loop
+                       }
+                       return
+               }
+
+               if q != nil {
+                       p.Mark |= FOLL
+                       p = q
+                       if p.Mark&FOLL == 0 {
+                               goto loop
+                       }
+               }
+       }
+
+       if p.Mark&FOLL != 0 {
+               i = 0
+               q = p
+               for ; i < 4; i, q = i+1, q.Link {
+                       if q == *last || (q.Mark&NOSCHED != 0) {
+                               break
+                       }
+                       b = 0 /* set */
+                       a = int(q.As)
+                       if a == obj.ANOP {
+                               i--
+                               continue
+                       }
+
+                       if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
+                               goto copy
+                       }
+                       if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) {
+                               continue
+                       }
+                       b = relinv(a)
+                       if b == 0 {
+                               continue
+                       }
+
+               copy:
+                       for {
+                               r = ctxt.NewProg()
+                               *r = *p
+                               if r.Mark&FOLL == 0 {
+                                       fmt.Printf("cant happen 1\n")
+                               }
+                               r.Mark |= FOLL
+                               if p != q {
+                                       p = p.Link
+                                       (*last).Link = r
+                                       *last = r
+                                       continue
+                               }
+
+                               (*last).Link = r
+                               *last = r
+                               if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
+                                       return
+                               }
+                               r.As = int16(b)
+                               r.Pcond = p.Link
+                               r.Link = p.Pcond
+                               if r.Link.Mark&FOLL == 0 {
+                                       xfol(ctxt, r.Link, last)
+                               }
+                               if r.Pcond.Mark&FOLL == 0 {
+                                       fmt.Printf("cant happen 2\n")
+                               }
+                               return
+                       }
+               }
+
+               a = ABR
+               q = ctxt.NewProg()
+               q.As = int16(a)
+               q.Lineno = p.Lineno
+               q.To.Type = obj.TYPE_BRANCH
+               q.To.Offset = p.Pc
+               q.Pcond = p
+               p = q
+       }
+
+       p.Mark |= FOLL
+       (*last).Link = p
+       *last = p
+       if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
+               if p.Mark&NOSCHED != 0 {
+                       p = p.Link
+                       goto loop
+               }
+
+               return
+       }
+
+       if p.Pcond != nil {
+               if a != ABL && p.Link != nil {
+                       xfol(ctxt, p.Link, last)
+                       p = p.Pcond
+                       if p == nil || (p.Mark&FOLL != 0) {
+                               return
+                       }
+                       goto loop
+               }
+       }
+
+       p = p.Link
+       goto loop
+}
+
+var Linkppc64 = obj.LinkArch{
+       ByteOrder:  binary.BigEndian,
+       Name:       "ppc64",
+       Thechar:    '9',
+       Preprocess: preprocess,
+       Assemble:   span9,
+       Follow:     follow,
+       Progedit:   progedit,
+       Minlc:      4,
+       Ptrsize:    8,
+       Regsize:    8,
+}
+
+var Linkppc64le = obj.LinkArch{
+       ByteOrder:  binary.LittleEndian,
+       Name:       "ppc64le",
+       Thechar:    '9',
+       Preprocess: preprocess,
+       Assemble:   span9,
+       Follow:     follow,
+       Progedit:   progedit,
+       Minlc:      4,
+       Ptrsize:    8,
+       Regsize:    8,
+}