From: Shenghou Ma Date: Sun, 6 Sep 2015 00:27:00 +0000 (-0400) Subject: cmd/internal/obj/mips: copy cmd/internal/obj/ppc64 X-Git-Tag: go1.6beta1~1148 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=5cc86c6f5510799b941f9d1ab405025ee6b8069a;p=gostls13.git cmd/internal/obj/mips: copy cmd/internal/obj/ppc64 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 --- diff --git a/src/cmd/internal/obj/mips/a.out.go b/src/cmd/internal/obj/mips/a.out.go new file mode 100644 index 0000000000..3028b6cac8 --- /dev/null +++ b/src/cmd/internal/obj/mips/a.out.go @@ -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 index 0000000000..1ae7a52015 --- /dev/null +++ b/src/cmd/internal/obj/mips/anames.go @@ -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 index 0000000000..b48e5162b0 --- /dev/null +++ b/src/cmd/internal/obj/mips/anames0.go @@ -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 index 0000000000..2955a0023d --- /dev/null +++ b/src/cmd/internal/obj/mips/asm0.go @@ -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<= 32 || v&(1<= 64 || v&(uint64(1)<> 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 index 0000000000..4cdcfbcd27 --- /dev/null +++ b/src/cmd/internal/obj/mips/list0.go @@ -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 index 0000000000..1eddc6fc6c --- /dev/null +++ b/src/cmd/internal/obj/mips/obj0.go @@ -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, +}