diff options
Diffstat (limited to 'vendor/github.com/twitchyliquid64/golang-asm/obj/arm/asm5.go')
-rw-r--r-- | vendor/github.com/twitchyliquid64/golang-asm/obj/arm/asm5.go | 3096 |
1 files changed, 0 insertions, 3096 deletions
diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/asm5.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/asm5.go deleted file mode 100644 index 924657fb3..000000000 --- a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm/asm5.go +++ /dev/null @@ -1,3096 +0,0 @@ -// Inferno utils/5l/span.c -// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/span.c -// -// 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-2007 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-2007 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 arm - -import ( - "github.com/twitchyliquid64/golang-asm/obj" - "github.com/twitchyliquid64/golang-asm/objabi" - "fmt" - "log" - "math" - "sort" -) - -// ctxt5 holds state while assembling a single function. -// Each function gets a fresh ctxt5. -// This allows for multiple functions to be safely concurrently assembled. -type ctxt5 struct { - ctxt *obj.Link - newprog obj.ProgAlloc - cursym *obj.LSym - printp *obj.Prog - blitrl *obj.Prog - elitrl *obj.Prog - autosize int64 - instoffset int64 - pc int64 - pool struct { - start uint32 - size uint32 - extra uint32 - } -} - -type Optab struct { - as obj.As - a1 uint8 - a2 int8 - a3 uint8 - type_ uint8 - size int8 - param int16 - flag int8 - pcrelsiz uint8 - scond uint8 // optional flags accepted by the instruction -} - -type Opcross [32][2][32]uint8 - -const ( - LFROM = 1 << 0 - LTO = 1 << 1 - LPOOL = 1 << 2 - LPCREL = 1 << 3 -) - -var optab = []Optab{ - /* struct Optab: - OPCODE, from, prog->reg, to, type, size, param, flag, extra data size, optional suffix */ - {obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0, 0}, - {AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT}, - {AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, - {AAND, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT}, - {AAND, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, - {AORR, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT}, - {AORR, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, - {AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, - {AMVN, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, - {ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0, 0}, - {AADD, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT}, - {AADD, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT}, - {AAND, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT}, - {AAND, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT}, - {AORR, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT}, - {AORR, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT}, - {AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, 0}, - {AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, 0}, - {ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0, 0, 0, 0}, - {AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT}, - {AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, - {AAND, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT}, - {AAND, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, - {AORR, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT}, - {AORR, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, - {AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, - {ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0, 0}, - {AMOVW, C_RACON, C_NONE, C_REG, 4, 4, REGSP, 0, 0, C_SBIT}, - {AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL, 0, 0}, - {ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, - {ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0, 0, 0, 0}, - {ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, - {ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // prediction hinted form, hint ignored - {AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL, 0, 0}, - {ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0, 0, 0, 0}, - {ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0, 0, 0, 0}, - {ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0, 0, 0, 0}, - {ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0, 0, 0, 0}, - {ASLL, C_RCON, C_REG, C_REG, 8, 4, 0, 0, 0, C_SBIT}, - {ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0, 0, 0, C_SBIT}, - {ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0, C_SBIT}, - {ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0, C_SBIT}, - {ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0, 0}, - {ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0, 0, 0, 0}, - {AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0, 0, 0, 0}, - {AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0, 0, 0, 0}, - {AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0, 0, 0, 0}, - {AWORD, C_NONE, C_NONE, C_TLS_LE, 103, 4, 0, 0, 0, 0}, - {AWORD, C_NONE, C_NONE, C_TLS_IE, 104, 4, 0, 0, 0, 0}, - {AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0}, - {AMOVW, C_SCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0}, - {AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0, 0}, - {AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4, 0}, - {AMVN, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0}, - {AADD, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {AADD, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {AAND, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {AAND, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {AORR, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {AORR, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0, 0, 0, 0}, - {AADD, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {AADD, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {AAND, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {AAND, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {AORR, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {AORR, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, - {AMVN, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, 0}, - {ACMP, C_SCON, C_REG, C_NONE, 13, 8, 0, 0, 0, 0}, - {AADD, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0, 0}, - {AADD, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0, 0}, - {AORR, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0, 0}, - {AORR, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0, 0}, - {AADD, C_RCON2S, C_REG, C_REG, 107, 8, 0, 0, 0, 0}, - {AADD, C_RCON2S, C_NONE, C_REG, 107, 8, 0, 0, 0, 0}, - {AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, - {AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, - {AAND, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, - {AAND, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, - {AORR, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, - {AORR, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, - {AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, 0}, - {ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0, 0}, - {AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, 0}, - {AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0}, - {AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0, 0, 0, 0}, - {AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, 0}, - {AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0}, - {AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0}, - {AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0, C_SBIT}, - {AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0, C_SBIT}, - {ADIV, C_REG, C_REG, C_REG, 16, 4, 0, 0, 0, 0}, - {ADIV, C_REG, C_NONE, C_REG, 16, 4, 0, 0, 0, 0}, - {ADIVHW, C_REG, C_REG, C_REG, 105, 4, 0, 0, 0, 0}, - {ADIVHW, C_REG, C_NONE, C_REG, 105, 4, 0, 0, 0, 0}, - {AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0, C_SBIT}, - {ABFX, C_LCON, C_REG, C_REG, 18, 4, 0, 0, 0, 0}, // width in From, LSB in From3 - {ABFX, C_LCON, C_NONE, C_REG, 18, 4, 0, 0, 0, 0}, // width in From, LSB in From3 - {AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVW, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVW, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AXTAB, C_SHIFT, C_REG, C_REG, 22, 4, 0, 0, 0, 0}, - {AXTAB, C_SHIFT, C_NONE, C_REG, 22, 4, 0, 0, 0, 0}, - {AMOVW, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, C_SBIT}, - {AMOVB, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, - {AMOVBS, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, - {AMOVBU, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, - {AMOVH, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, - {AMOVHS, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, - {AMOVHU, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, - {AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVW, C_TLS_LE, C_NONE, C_REG, 101, 4, 0, LFROM, 0, 0}, - {AMOVW, C_TLS_IE, C_NONE, C_REG, 102, 8, 0, LFROM, 0, 0}, - {AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVW, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0, C_SBIT}, - {AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0, 0, 0, 0}, - {AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0, 0, 0, 0}, - {AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0, 0, 0, 0}, - {AMOVM, C_REGLIST, C_NONE, C_SOREG, 38, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVM, C_SOREG, C_NONE, C_REGLIST, 39, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {ASWPW, C_SOREG, C_REG, C_REG, 40, 4, 0, 0, 0, 0}, - {ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0, 0}, - {AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVF, C_FAUTO, C_NONE, C_FREG, 51, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVF, C_FOREG, C_NONE, C_FREG, 51, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVF, C_LAUTO, C_NONE, C_FREG, 53, 12, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVF, C_LOREG, C_NONE, C_FREG, 53, 12, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0, 0}, - {AADDF, C_FREG, C_FREG, C_FREG, 54, 4, 0, 0, 0, 0}, - {AMOVF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0, 0}, - {ANEGF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0, 0}, - {AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0, 0, 0, 0}, - {AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0, 0, 0, 0}, - {AMOVW, C_SHIFTADDR, C_NONE, C_REG, 59, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_SHIFTADDR, C_NONE, C_REG, 59, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVW, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBU, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, - {AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, - {ALDREX, C_SOREG, C_NONE, C_REG, 77, 4, 0, 0, 0, 0}, - {ASTREX, C_SOREG, C_REG, C_REG, 78, 4, 0, 0, 0, 0}, - {ADMB, C_NONE, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0}, - {ADMB, C_LCON, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0}, - {ADMB, C_SPR, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0}, - {AMOVF, C_ZFCON, C_NONE, C_FREG, 80, 8, 0, 0, 0, 0}, - {AMOVF, C_SFCON, C_NONE, C_FREG, 81, 4, 0, 0, 0, 0}, - {ACMPF, C_FREG, C_FREG, C_NONE, 82, 8, 0, 0, 0, 0}, - {ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0, 0, 0, 0}, - {AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0, 0, 0, C_UBIT}, - {AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0, 0, 0, C_UBIT}, - {AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0, 0, 0, C_UBIT}, - {AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0, 0, 0, C_UBIT}, - {AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0, 0, 0, 0}, - {AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0, 0, 0, 0}, - {ALDREXD, C_SOREG, C_NONE, C_REG, 91, 4, 0, 0, 0, 0}, - {ASTREXD, C_SOREG, C_REG, C_REG, 92, 4, 0, 0, 0, 0}, - {APLD, C_SOREG, C_NONE, C_NONE, 95, 4, 0, 0, 0, 0}, - {obj.AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0, 0, 0, 0}, - {ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0, 0}, - {AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0, 0}, - {AMULA, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0, C_SBIT}, - {AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0, 0}, - {obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0, 0}, - {obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0, 0}, - {obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, - {obj.ANOP, C_LCON, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, // nop variants, see #40689 - {obj.ANOP, C_REG, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, - {obj.ANOP, C_FREG, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, - {obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // same as ABL - {obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // same as ABL - {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0, 0}, -} - -var mbOp = []struct { - reg int16 - enc uint32 -}{ - {REG_MB_SY, 15}, - {REG_MB_ST, 14}, - {REG_MB_ISH, 11}, - {REG_MB_ISHST, 10}, - {REG_MB_NSH, 7}, - {REG_MB_NSHST, 6}, - {REG_MB_OSH, 3}, - {REG_MB_OSHST, 2}, -} - -var oprange [ALAST & obj.AMask][]Optab - -var xcmp [C_GOK + 1][C_GOK + 1]bool - -var ( - deferreturn *obj.LSym - symdiv *obj.LSym - symdivu *obj.LSym - symmod *obj.LSym - symmodu *obj.LSym -) - -// Note about encoding: Prog.scond holds the condition encoding, -// but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0. -// The code that shifts the value << 28 has the responsibility -// for XORing with C_SCOND_XOR too. - -func checkSuffix(c *ctxt5, p *obj.Prog, o *Optab) { - if p.Scond&C_SBIT != 0 && o.scond&C_SBIT == 0 { - c.ctxt.Diag("invalid .S suffix: %v", p) - } - if p.Scond&C_PBIT != 0 && o.scond&C_PBIT == 0 { - c.ctxt.Diag("invalid .P suffix: %v", p) - } - if p.Scond&C_WBIT != 0 && o.scond&C_WBIT == 0 { - c.ctxt.Diag("invalid .W suffix: %v", p) - } - if p.Scond&C_UBIT != 0 && o.scond&C_UBIT == 0 { - c.ctxt.Diag("invalid .U suffix: %v", p) - } -} - -func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { - if ctxt.Retpoline { - ctxt.Diag("-spectre=ret not supported on arm") - ctxt.Retpoline = false // don't keep printing - } - - var p *obj.Prog - var op *obj.Prog - - p = cursym.Func.Text - if p == nil || p.Link == nil { // handle external functions and ELF section symbols - return - } - - if oprange[AAND&obj.AMask] == nil { - ctxt.Diag("arm ops not initialized, call arm.buildop first") - } - - c := ctxt5{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: p.To.Offset + 4} - pc := int32(0) - - op = p - p = p.Link - var m int - var o *Optab - for ; p != nil || c.blitrl != nil; op, p = p, p.Link { - if p == nil { - if c.checkpool(op, pc) { - p = op - continue - } - - // can't happen: blitrl is not nil, but checkpool didn't flushpool - ctxt.Diag("internal inconsistency") - - break - } - - p.Pc = int64(pc) - o = c.oplook(p) - m = int(o.size) - - if m%4 != 0 || p.Pc%4 != 0 { - ctxt.Diag("!pc invalid: %v size=%d", p, m) - } - - // must check literal pool here in case p generates many instructions - if c.blitrl != nil { - // Emit the constant pool just before p if p - // would push us over the immediate size limit. - if c.checkpool(op, pc+int32(m)) { - // Back up to the instruction just - // before the pool and continue with - // the first instruction of the pool. - p = op - continue - } - } - - if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) { - ctxt.Diag("zero-width instruction\n%v", p) - continue - } - - switch o.flag & (LFROM | LTO | LPOOL) { - case LFROM: - c.addpool(p, &p.From) - - case LTO: - c.addpool(p, &p.To) - - case LPOOL: - if p.Scond&C_SCOND == C_SCOND_NONE { - c.flushpool(p, 0, 0) - } - } - - if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE { - c.flushpool(p, 0, 0) - } - - pc += int32(m) - } - - c.cursym.Size = int64(pc) - - /* - * if any procedure is large enough to - * generate a large SBRA branch, then - * generate extra passes putting branches - * around jmps to fix. this is rare. - */ - times := 0 - - var bflag int - var opc int32 - var out [6 + 3]uint32 - for { - bflag = 0 - pc = 0 - times++ - c.cursym.Func.Text.Pc = 0 // force re-layout the code. - for p = c.cursym.Func.Text; p != nil; p = p.Link { - o = c.oplook(p) - if int64(pc) > p.Pc { - p.Pc = int64(pc) - } - - /* very large branches - if(o->type == 6 && p->pcond) { - otxt = p->pcond->pc - c; - if(otxt < 0) - otxt = -otxt; - if(otxt >= (1L<<17) - 10) { - q = emallocz(sizeof(Prog)); - q->link = p->link; - p->link = q; - q->as = AB; - q->to.type = TYPE_BRANCH; - q->pcond = p->pcond; - p->pcond = q; - q = emallocz(sizeof(Prog)); - q->link = p->link; - p->link = q; - q->as = AB; - q->to.type = TYPE_BRANCH; - q->pcond = q->link->link; - bflag = 1; - } - } - */ - opc = int32(p.Pc) - m = int(o.size) - if p.Pc != int64(opc) { - bflag = 1 - } - - //print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times); - pc = int32(p.Pc + int64(m)) - - if m%4 != 0 || p.Pc%4 != 0 { - ctxt.Diag("pc invalid: %v size=%d", p, m) - } - - if m/4 > len(out) { - ctxt.Diag("instruction size too large: %d > %d", m/4, len(out)) - } - if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) { - if p.As == obj.ATEXT { - c.autosize = p.To.Offset + 4 - continue - } - - ctxt.Diag("zero-width instruction\n%v", p) - continue - } - } - - c.cursym.Size = int64(pc) - if bflag == 0 { - break - } - } - - if pc%4 != 0 { - ctxt.Diag("sym->size=%d, invalid", pc) - } - - /* - * lay out the code. all the pc-relative code references, - * even cross-function, are resolved now; - * only data references need to be relocated. - * with more work we could leave cross-function - * code references to be relocated too, and then - * perhaps we'd be able to parallelize the span loop above. - */ - - p = c.cursym.Func.Text - c.autosize = p.To.Offset + 4 - c.cursym.Grow(c.cursym.Size) - - bp := c.cursym.P - pc = int32(p.Pc) // even p->link might need extra padding - var v int - for p = p.Link; p != nil; p = p.Link { - c.pc = p.Pc - o = c.oplook(p) - opc = int32(p.Pc) - c.asmout(p, o, out[:]) - m = int(o.size) - - if m%4 != 0 || p.Pc%4 != 0 { - ctxt.Diag("final stage: pc invalid: %v size=%d", p, m) - } - - if int64(pc) > p.Pc { - ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, pc, p) - } - for int64(pc) != p.Pc { - // emit 0xe1a00000 (MOVW R0, R0) - bp[0] = 0x00 - bp = bp[1:] - - bp[0] = 0x00 - bp = bp[1:] - bp[0] = 0xa0 - bp = bp[1:] - bp[0] = 0xe1 - bp = bp[1:] - pc += 4 - } - - for i := 0; i < m/4; i++ { - v = int(out[i]) - bp[0] = byte(v) - bp = bp[1:] - bp[0] = byte(v >> 8) - bp = bp[1:] - bp[0] = byte(v >> 16) - bp = bp[1:] - bp[0] = byte(v >> 24) - bp = bp[1:] - } - - pc += int32(m) - } -} - -// checkpool flushes the literal pool when the first reference to -// it threatens to go out of range of a 12-bit PC-relative offset. -// -// nextpc is the tentative next PC at which the pool could be emitted. -// checkpool should be called *before* emitting the instruction that -// would cause the PC to reach nextpc. -// If nextpc is too far from the first pool reference, checkpool will -// flush the pool immediately after p. -// The caller should resume processing a p.Link. -func (c *ctxt5) checkpool(p *obj.Prog, nextpc int32) bool { - poolLast := nextpc - poolLast += 4 // the AB instruction to jump around the pool - poolLast += int32(c.pool.size) - 4 // the offset of the last pool entry - - refPC := int32(c.pool.start) // PC of the first pool reference - - v := poolLast - refPC - 8 // 12-bit PC-relative offset (see omvl) - - if c.pool.size >= 0xff0 || immaddr(v) == 0 { - return c.flushpool(p, 1, 0) - } else if p.Link == nil { - return c.flushpool(p, 2, 0) - } - return false -} - -func (c *ctxt5) flushpool(p *obj.Prog, skip int, force int) bool { - if c.blitrl != nil { - if skip != 0 { - if false && skip == 1 { - fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), c.pool.size, c.pool.start) - } - q := c.newprog() - q.As = AB - q.To.Type = obj.TYPE_BRANCH - q.To.SetTarget(p.Link) - q.Link = c.blitrl - q.Pos = p.Pos - c.blitrl = q - } else if force == 0 && (p.Pc+int64(c.pool.size)-int64(c.pool.start) < 2048) { - return false - } - - // The line number for constant pool entries doesn't really matter. - // We set it to the line number of the preceding instruction so that - // there are no deltas to encode in the pc-line tables. - for q := c.blitrl; q != nil; q = q.Link { - q.Pos = p.Pos - } - - c.elitrl.Link = p.Link - p.Link = c.blitrl - - c.blitrl = nil /* BUG: should refer back to values until out-of-range */ - c.elitrl = nil - c.pool.size = 0 - c.pool.start = 0 - c.pool.extra = 0 - return true - } - - return false -} - -func (c *ctxt5) addpool(p *obj.Prog, a *obj.Addr) { - t := c.newprog() - t.As = AWORD - - switch c.aclass(a) { - default: - t.To.Offset = a.Offset - t.To.Sym = a.Sym - t.To.Type = a.Type - t.To.Name = a.Name - - if c.ctxt.Flag_shared && t.To.Sym != nil { - t.Rel = p - } - - case C_SROREG, - C_LOREG, - C_ROREG, - C_FOREG, - C_SOREG, - C_HOREG, - C_FAUTO, - C_SAUTO, - C_LAUTO, - C_LACON: - t.To.Type = obj.TYPE_CONST - t.To.Offset = c.instoffset - } - - if t.Rel == nil { - for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */ - if q.Rel == nil && q.To == t.To { - p.Pool = q - return - } - } - } - - q := c.newprog() - *q = *t - q.Pc = int64(c.pool.size) - - if c.blitrl == nil { - c.blitrl = q - c.pool.start = uint32(p.Pc) - } else { - c.elitrl.Link = q - } - c.elitrl = q - c.pool.size += 4 - - // Store the link to the pool entry in Pool. - p.Pool = q -} - -func (c *ctxt5) regoff(a *obj.Addr) int32 { - c.instoffset = 0 - c.aclass(a) - return int32(c.instoffset) -} - -func immrot(v uint32) int32 { - for i := 0; i < 16; i++ { - if v&^0xff == 0 { - return int32(uint32(int32(i)<<8) | v | 1<<25) - } - v = v<<2 | v>>30 - } - - return 0 -} - -// immrot2a returns bits encoding the immediate constant fields of two instructions, -// such that the encoded constants x, y satisfy x|y==v, x&y==0. -// Returns 0,0 if no such decomposition of v exists. -func immrot2a(v uint32) (uint32, uint32) { - for i := uint(1); i < 32; i++ { - m := uint32(1<<i - 1) - if x, y := immrot(v&m), immrot(v&^m); x != 0 && y != 0 { - return uint32(x), uint32(y) - } - } - // TODO: handle some more cases, like where - // the wraparound from the rotate could help. - return 0, 0 -} - -// immrot2s returns bits encoding the immediate constant fields of two instructions, -// such that the encoded constants y, x satisfy y-x==v, y&x==0. -// Returns 0,0 if no such decomposition of v exists. -func immrot2s(v uint32) (uint32, uint32) { - if immrot(v) != 0 { - return v, 0 - } - // suppose v in the form of {leading 00, upper effective bits, lower 8 effective bits, trailing 00} - // omit trailing 00 - var i uint32 - for i = 2; i < 32; i += 2 { - if v&(1<<i-1) != 0 { - break - } - } - // i must be <= 24, then adjust i just above lower 8 effective bits of v - i += 6 - // let x = {the complement of lower 8 effective bits, trailing 00}, y = x + v - x := 1<<i - v&(1<<i-1) - y := v + x - if y, x = uint32(immrot(y)), uint32(immrot(x)); y != 0 && x != 0 { - return y, x - } - return 0, 0 -} - -func immaddr(v int32) int32 { - if v >= 0 && v <= 0xfff { - return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */ - } - if v >= -0xfff && v < 0 { - return -v&0xfff | 1<<24 /* pre indexing */ - } - return 0 -} - -func immfloat(v int32) bool { - return v&0xC03 == 0 /* offset will fit in floating-point load/store */ -} - -func immhalf(v int32) bool { - if v >= 0 && v <= 0xff { - return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */ - } - if v >= -0xff && v < 0 { - return -v&0xff|1<<24 != 0 /* pre indexing */ - } - return false -} - -func (c *ctxt5) aclass(a *obj.Addr) int { - switch a.Type { - case obj.TYPE_NONE: - return C_NONE - - case obj.TYPE_REG: - c.instoffset = 0 - if REG_R0 <= a.Reg && a.Reg <= REG_R15 { - return C_REG - } - if REG_F0 <= a.Reg && a.Reg <= REG_F15 { - return C_FREG - } - if a.Reg == REG_FPSR || a.Reg == REG_FPCR { - return C_FCR - } - if a.Reg == REG_CPSR || a.Reg == REG_SPSR { - return C_PSR - } - if a.Reg >= REG_SPECIAL { - return C_SPR - } - return C_GOK - - case obj.TYPE_REGREG: - return C_REGREG - - case obj.TYPE_REGREG2: - return C_REGREG2 - - case obj.TYPE_REGLIST: - return C_REGLIST - - case obj.TYPE_SHIFT: - if a.Reg == 0 { - // register shift R>>i - return C_SHIFT - } else { - // memory address with shifted offset R>>i(R) - return C_SHIFTADDR - } - - case obj.TYPE_MEM: - switch a.Name { - case obj.NAME_EXTERN, - obj.NAME_GOTREF, - obj.NAME_STATIC: - if a.Sym == nil || a.Sym.Name == "" { - fmt.Printf("null sym external\n") - return C_GOK - } - - c.instoffset = 0 // s.b. unused but just in case - if a.Sym.Type == objabi.STLSBSS { - if c.ctxt.Flag_shared { - return C_TLS_IE - } else { - return C_TLS_LE - } - } - - return C_ADDR - - case obj.NAME_AUTO: - if a.Reg == REGSP { - // unset base register for better printing, since - // a.Offset is still relative to pseudo-SP. - a.Reg = obj.REG_NONE - } - c.instoffset = c.autosize + a.Offset - if t := immaddr(int32(c.instoffset)); t != 0 { - if immhalf(int32(c.instoffset)) { - if immfloat(t) { - return C_HFAUTO - } - return C_HAUTO - } - - if immfloat(t) { - return C_FAUTO - } - return C_SAUTO - } - - return C_LAUTO - - case obj.NAME_PARAM: - if a.Reg == REGSP { - // unset base register for better printing, since - // a.Offset is still relative to pseudo-FP. - a.Reg = obj.REG_NONE - } - c.instoffset = c.autosize + a.Offset + 4 - if t := immaddr(int32(c.instoffset)); t != 0 { - if immhalf(int32(c.instoffset)) { - if immfloat(t) { - return C_HFAUTO - } - return C_HAUTO - } - - if immfloat(t) { - return C_FAUTO - } - return C_SAUTO - } - - return C_LAUTO - - case obj.NAME_NONE: - c.instoffset = a.Offset - if t := immaddr(int32(c.instoffset)); t != 0 { - if immhalf(int32(c.instoffset)) { /* n.b. that it will also satisfy immrot */ - if immfloat(t) { - return C_HFOREG - } - return C_HOREG - } - - if immfloat(t) { - return C_FOREG /* n.b. that it will also satisfy immrot */ - } - if immrot(uint32(c.instoffset)) != 0 { - return C_SROREG - } - if immhalf(int32(c.instoffset)) { - return C_HOREG - } - return C_SOREG - } - - if immrot(uint32(c.instoffset)) != 0 { - return C_ROREG - } - return C_LOREG - } - - return C_GOK - - case obj.TYPE_FCONST: - if c.chipzero5(a.Val.(float64)) >= 0 { - return C_ZFCON - } - if c.chipfloat5(a.Val.(float64)) >= 0 { - return C_SFCON - } - return C_LFCON - - case obj.TYPE_TEXTSIZE: - return C_TEXTSIZE - - case obj.TYPE_CONST, - obj.TYPE_ADDR: - switch a.Name { - case obj.NAME_NONE: - c.instoffset = a.Offset - if a.Reg != 0 { - return c.aconsize() - } - - if immrot(uint32(c.instoffset)) != 0 { - return C_RCON - } - if immrot(^uint32(c.instoffset)) != 0 { - return C_NCON - } - if uint32(c.instoffset) <= 0xffff && objabi.GOARM == 7 { - return C_SCON - } - if x, y := immrot2a(uint32(c.instoffset)); x != 0 && y != 0 { - return C_RCON2A - } - if y, x := immrot2s(uint32(c.instoffset)); x != 0 && y != 0 { - return C_RCON2S - } - return C_LCON - - case obj.NAME_EXTERN, - obj.NAME_GOTREF, - obj.NAME_STATIC: - s := a.Sym - if s == nil { - break - } - c.instoffset = 0 // s.b. unused but just in case - return C_LCONADDR - - case obj.NAME_AUTO: - if a.Reg == REGSP { - // unset base register for better printing, since - // a.Offset is still relative to pseudo-SP. - a.Reg = obj.REG_NONE - } - c.instoffset = c.autosize + a.Offset - return c.aconsize() - - case obj.NAME_PARAM: - if a.Reg == REGSP { - // unset base register for better printing, since - // a.Offset is still relative to pseudo-FP. - a.Reg = obj.REG_NONE - } - c.instoffset = c.autosize + a.Offset + 4 - return c.aconsize() - } - - return C_GOK - - case obj.TYPE_BRANCH: - return C_SBRA - } - - return C_GOK -} - -func (c *ctxt5) aconsize() int { - if immrot(uint32(c.instoffset)) != 0 { - return C_RACON - } - if immrot(uint32(-c.instoffset)) != 0 { - return C_RACON - } - return C_LACON -} - -func (c *ctxt5) oplook(p *obj.Prog) *Optab { - a1 := int(p.Optab) - if a1 != 0 { - return &optab[a1-1] - } - a1 = int(p.From.Class) - if a1 == 0 { - a1 = c.aclass(&p.From) + 1 - p.From.Class = int8(a1) - } - - a1-- - a3 := int(p.To.Class) - if a3 == 0 { - a3 = c.aclass(&p.To) + 1 - p.To.Class = int8(a3) - } - - a3-- - a2 := C_NONE - if p.Reg != 0 { - switch { - case REG_F0 <= p.Reg && p.Reg <= REG_F15: - a2 = C_FREG - case REG_R0 <= p.Reg && p.Reg <= REG_R15: - a2 = C_REG - default: - c.ctxt.Diag("invalid register in %v", p) - } - } - - // check illegal base register - switch a1 { - case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR: - if p.From.Reg < REG_R0 || REG_R15 < p.From.Reg { - c.ctxt.Diag("illegal base register: %v", p) - } - default: - } - switch a3 { - case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR: - if p.To.Reg < REG_R0 || REG_R15 < p.To.Reg { - c.ctxt.Diag("illegal base register: %v", p) - } - default: - } - - // If current instruction has a .S suffix (flags update), - // we must use the constant pool instead of splitting it. - if (a1 == C_RCON2A || a1 == C_RCON2S) && p.Scond&C_SBIT != 0 { - a1 = C_LCON - } - if (a3 == C_RCON2A || a3 == C_RCON2S) && p.Scond&C_SBIT != 0 { - a3 = C_LCON - } - - if false { /*debug['O']*/ - fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3)) - fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type) - } - - ops := oprange[p.As&obj.AMask] - c1 := &xcmp[a1] - c3 := &xcmp[a3] - for i := range ops { - op := &ops[i] - if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] { - p.Optab = uint16(cap(optab) - cap(ops) + i + 1) - checkSuffix(c, p, op) - return op - } - } - - c.ctxt.Diag("illegal combination %v; %v %v %v; from %d %d; to %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.From.Name, p.To.Type, p.To.Name) - if ops == nil { - ops = optab - } - return &ops[0] -} - -func cmp(a int, b int) bool { - if a == b { - return true - } - switch a { - case C_LCON: - if b == C_RCON || b == C_NCON || b == C_SCON || b == C_RCON2A || b == C_RCON2S { - return true - } - - case C_LACON: - if b == C_RACON { - return true - } - - case C_LFCON: - if b == C_ZFCON || b == C_SFCON { - return true - } - - case C_HFAUTO: - return b == C_HAUTO || b == C_FAUTO - - case C_FAUTO, C_HAUTO: - return b == C_HFAUTO - - case C_SAUTO: - return cmp(C_HFAUTO, b) - - case C_LAUTO: - return cmp(C_SAUTO, b) - - case C_HFOREG: - return b == C_HOREG || b == C_FOREG - - case C_FOREG, C_HOREG: - return b == C_HFOREG - - case C_SROREG: - return cmp(C_SOREG, b) || cmp(C_ROREG, b) - - case C_SOREG, C_ROREG: - return b == C_SROREG || cmp(C_HFOREG, b) - - case C_LOREG: - return cmp(C_SROREG, b) - - case C_LBRA: - if b == C_SBRA { - return true - } - - case C_HREG: - return cmp(C_SP, b) || cmp(C_PC, b) - } - - 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 - } - return false -} - -func opset(a, b0 obj.As) { - oprange[a&obj.AMask] = oprange[b0] -} - -func buildop(ctxt *obj.Link) { - if oprange[AAND&obj.AMask] != nil { - // Already initialized; stop now. - // This happens in the cmd/asm tests, - // each of which re-initializes the arch. - return - } - - deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal) - - symdiv = ctxt.Lookup("runtime._div") - symdivu = ctxt.Lookup("runtime._divu") - symmod = ctxt.Lookup("runtime._mod") - symmodu = ctxt.Lookup("runtime._modu") - - var n int - - for i := 0; i < C_GOK; i++ { - for n = 0; n < C_GOK; n++ { - if cmp(n, i) { - xcmp[i][n] = true - } - } - } - for n = 0; optab[n].as != obj.AXXX; n++ { - if optab[n].flag&LPCREL != 0 { - if ctxt.Flag_shared { - optab[n].size += int8(optab[n].pcrelsiz) - } else { - optab[n].flag &^= LPCREL - } - } - } - - sort.Sort(ocmp(optab[:n])) - for i := 0; i < n; i++ { - r := optab[i].as - r0 := r & obj.AMask - start := i - for optab[i].as == r { - i++ - } - oprange[r0] = optab[start:i] - i-- - - switch r { - default: - ctxt.Diag("unknown op in build: %v", r) - ctxt.DiagFlush() - log.Fatalf("bad code") - - case AADD: - opset(ASUB, r0) - opset(ARSB, r0) - opset(AADC, r0) - opset(ASBC, r0) - opset(ARSC, r0) - - case AORR: - opset(AEOR, r0) - opset(ABIC, r0) - - case ACMP: - opset(ATEQ, r0) - opset(ACMN, r0) - opset(ATST, r0) - - case AMVN: - break - - case ABEQ: - opset(ABNE, r0) - opset(ABCS, r0) - opset(ABHS, r0) - opset(ABCC, r0) - opset(ABLO, r0) - opset(ABMI, r0) - opset(ABPL, r0) - opset(ABVS, r0) - opset(ABVC, r0) - opset(ABHI, r0) - opset(ABLS, r0) - opset(ABGE, r0) - opset(ABLT, r0) - opset(ABGT, r0) - opset(ABLE, r0) - - case ASLL: - opset(ASRL, r0) - opset(ASRA, r0) - - case AMUL: - opset(AMULU, r0) - - case ADIV: - opset(AMOD, r0) - opset(AMODU, r0) - opset(ADIVU, r0) - - case ADIVHW: - opset(ADIVUHW, r0) - - case AMOVW, - AMOVB, - AMOVBS, - AMOVBU, - AMOVH, - AMOVHS, - AMOVHU: - break - - case ASWPW: - opset(ASWPBU, r0) - - case AB, - ABL, - ABX, - ABXRET, - obj.ADUFFZERO, - obj.ADUFFCOPY, - ASWI, - AWORD, - AMOVM, - ARFE, - obj.ATEXT: - break - - case AADDF: - opset(AADDD, r0) - opset(ASUBF, r0) - opset(ASUBD, r0) - opset(AMULF, r0) - opset(AMULD, r0) - opset(ANMULF, r0) - opset(ANMULD, r0) - opset(AMULAF, r0) - opset(AMULAD, r0) - opset(AMULSF, r0) - opset(AMULSD, r0) - opset(ANMULAF, r0) - opset(ANMULAD, r0) - opset(ANMULSF, r0) - opset(ANMULSD, r0) - opset(AFMULAF, r0) - opset(AFMULAD, r0) - opset(AFMULSF, r0) - opset(AFMULSD, r0) - opset(AFNMULAF, r0) - opset(AFNMULAD, r0) - opset(AFNMULSF, r0) - opset(AFNMULSD, r0) - opset(ADIVF, r0) - opset(ADIVD, r0) - - case ANEGF: - opset(ANEGD, r0) - opset(ASQRTF, r0) - opset(ASQRTD, r0) - opset(AMOVFD, r0) - opset(AMOVDF, r0) - opset(AABSF, r0) - opset(AABSD, r0) - - case ACMPF: - opset(ACMPD, r0) - - case AMOVF: - opset(AMOVD, r0) - - case AMOVFW: - opset(AMOVDW, r0) - - case AMOVWF: - opset(AMOVWD, r0) - - case AMULL: - opset(AMULAL, r0) - opset(AMULLU, r0) - opset(AMULALU, r0) - - case AMULWT: - opset(AMULWB, r0) - opset(AMULBB, r0) - opset(AMMUL, r0) - - case AMULAWT: - opset(AMULAWB, r0) - opset(AMULABB, r0) - opset(AMULS, r0) - opset(AMMULA, r0) - opset(AMMULS, r0) - - case ABFX: - opset(ABFXU, r0) - opset(ABFC, r0) - opset(ABFI, r0) - - case ACLZ: - opset(AREV, r0) - opset(AREV16, r0) - opset(AREVSH, r0) - opset(ARBIT, r0) - - case AXTAB: - opset(AXTAH, r0) - opset(AXTABU, r0) - opset(AXTAHU, r0) - - case ALDREX, - ASTREX, - ALDREXD, - ASTREXD, - ADMB, - APLD, - AAND, - AMULA, - obj.AUNDEF, - obj.AFUNCDATA, - obj.APCDATA, - obj.ANOP: - break - } - } -} - -func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) { - c.printp = p - o1 := uint32(0) - o2 := uint32(0) - o3 := uint32(0) - o4 := uint32(0) - o5 := uint32(0) - o6 := uint32(0) - if false { /*debug['P']*/ - fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_) - } - switch o.type_ { - default: - c.ctxt.Diag("%v: unknown asm %d", p, o.type_) - - case 0: /* pseudo ops */ - if false { /*debug['G']*/ - fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name) - } - - case 1: /* op R,[R],R */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - rf := int(p.From.Reg) - rt := int(p.To.Reg) - r := int(p.Reg) - if p.To.Type == obj.TYPE_NONE { - rt = 0 - } - if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN { - r = 0 - } else if r == 0 { - r = rt - } - o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 - - case 2: /* movbu $I,[R],R */ - c.aclass(&p.From) - - o1 = c.oprrr(p, p.As, int(p.Scond)) - o1 |= uint32(immrot(uint32(c.instoffset))) - rt := int(p.To.Reg) - r := int(p.Reg) - if p.To.Type == obj.TYPE_NONE { - rt = 0 - } - if p.As == AMOVW || p.As == AMVN { - r = 0 - } else if r == 0 { - r = rt - } - o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 - - case 106: /* op $I,R,R where I can be decomposed into 2 immediates */ - c.aclass(&p.From) - r := int(p.Reg) - rt := int(p.To.Reg) - if r == 0 { - r = rt - } - x, y := immrot2a(uint32(c.instoffset)) - var as2 obj.As - switch p.As { - case AADD, ASUB, AORR, AEOR, ABIC: - as2 = p.As // ADD, SUB, ORR, EOR, BIC - case ARSB: - as2 = AADD // RSB -> RSB/ADD pair - case AADC: - as2 = AADD // ADC -> ADC/ADD pair - case ASBC: - as2 = ASUB // SBC -> SBC/SUB pair - case ARSC: - as2 = AADD // RSC -> RSC/ADD pair - default: - c.ctxt.Diag("unknown second op for %v", p) - } - o1 = c.oprrr(p, p.As, int(p.Scond)) - o2 = c.oprrr(p, as2, int(p.Scond)) - o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 - o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12 - o1 |= x - o2 |= y - - case 107: /* op $I,R,R where I can be decomposed into 2 immediates */ - c.aclass(&p.From) - r := int(p.Reg) - rt := int(p.To.Reg) - if r == 0 { - r = rt - } - y, x := immrot2s(uint32(c.instoffset)) - var as2 obj.As - switch p.As { - case AADD: - as2 = ASUB // ADD -> ADD/SUB pair - case ASUB: - as2 = AADD // SUB -> SUB/ADD pair - case ARSB: - as2 = ASUB // RSB -> RSB/SUB pair - case AADC: - as2 = ASUB // ADC -> ADC/SUB pair - case ASBC: - as2 = AADD // SBC -> SBC/ADD pair - case ARSC: - as2 = ASUB // RSC -> RSC/SUB pair - default: - c.ctxt.Diag("unknown second op for %v", p) - } - o1 = c.oprrr(p, p.As, int(p.Scond)) - o2 = c.oprrr(p, as2, int(p.Scond)) - o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 - o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12 - o1 |= y - o2 |= x - - case 3: /* add R<<[IR],[R],R */ - o1 = c.mov(p) - - case 4: /* MOVW $off(R), R -> add $off,[R],R */ - c.aclass(&p.From) - if c.instoffset < 0 { - o1 = c.oprrr(p, ASUB, int(p.Scond)) - o1 |= uint32(immrot(uint32(-c.instoffset))) - } else { - o1 = c.oprrr(p, AADD, int(p.Scond)) - o1 |= uint32(immrot(uint32(c.instoffset))) - } - r := int(p.From.Reg) - if r == 0 { - r = int(o.param) - } - o1 |= (uint32(r) & 15) << 16 - o1 |= (uint32(p.To.Reg) & 15) << 12 - - case 5: /* bra s */ - o1 = c.opbra(p, p.As, int(p.Scond)) - - v := int32(-8) - if p.To.Sym != nil { - rel := obj.Addrel(c.cursym) - rel.Off = int32(c.pc) - rel.Siz = 4 - rel.Sym = p.To.Sym - v += int32(p.To.Offset) - rel.Add = int64(o1) | (int64(v)>>2)&0xffffff - rel.Type = objabi.R_CALLARM - break - } - - if p.To.Target() != nil { - v = int32((p.To.Target().Pc - c.pc) - 8) - } - o1 |= (uint32(v) >> 2) & 0xffffff - - case 6: /* b ,O(R) -> add $O,R,PC */ - c.aclass(&p.To) - - o1 = c.oprrr(p, AADD, int(p.Scond)) - o1 |= uint32(immrot(uint32(c.instoffset))) - o1 |= (uint32(p.To.Reg) & 15) << 16 - o1 |= (REGPC & 15) << 12 - - case 7: /* bl (R) -> blx R */ - c.aclass(&p.To) - - if c.instoffset != 0 { - c.ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, c.instoffset) - } - o1 = c.oprrr(p, ABL, int(p.Scond)) - o1 |= (uint32(p.To.Reg) & 15) << 0 - rel := obj.Addrel(c.cursym) - rel.Off = int32(c.pc) - rel.Siz = 0 - rel.Type = objabi.R_CALLIND - - case 8: /* sll $c,[R],R -> mov (R<<$c),R */ - c.aclass(&p.From) - - o1 = c.oprrr(p, p.As, int(p.Scond)) - r := int(p.Reg) - if r == 0 { - r = int(p.To.Reg) - } - o1 |= (uint32(r) & 15) << 0 - o1 |= uint32((c.instoffset & 31) << 7) - o1 |= (uint32(p.To.Reg) & 15) << 12 - - case 9: /* sll R,[R],R -> mov (R<<R),R */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - r := int(p.Reg) - if r == 0 { - r = int(p.To.Reg) - } - o1 |= (uint32(r) & 15) << 0 - o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4 - o1 |= (uint32(p.To.Reg) & 15) << 12 - - case 10: /* swi [$con] */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - if p.To.Type != obj.TYPE_NONE { - c.aclass(&p.To) - o1 |= uint32(c.instoffset & 0xffffff) - } - - case 11: /* word */ - c.aclass(&p.To) - - o1 = uint32(c.instoffset) - if p.To.Sym != nil { - // This case happens with words generated - // in the PC stream as part of the literal pool (c.pool). - rel := obj.Addrel(c.cursym) - - rel.Off = int32(c.pc) - rel.Siz = 4 - rel.Sym = p.To.Sym - rel.Add = p.To.Offset - - if c.ctxt.Flag_shared { - if p.To.Name == obj.NAME_GOTREF { - rel.Type = objabi.R_GOTPCREL - } else { - rel.Type = objabi.R_PCREL - } - rel.Add += c.pc - p.Rel.Pc - 8 - } else { - rel.Type = objabi.R_ADDR - } - o1 = 0 - } - - case 12: /* movw $lcon, reg */ - if o.a1 == C_SCON { - o1 = c.omvs(p, &p.From, int(p.To.Reg)) - } else if p.As == AMVN { - o1 = c.omvr(p, &p.From, int(p.To.Reg)) - } else { - o1 = c.omvl(p, &p.From, int(p.To.Reg)) - } - - if o.flag&LPCREL != 0 { - o2 = c.oprrr(p, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12 - } - - case 13: /* op $lcon, [R], R */ - if o.a1 == C_SCON { - o1 = c.omvs(p, &p.From, REGTMP) - } else { - o1 = c.omvl(p, &p.From, REGTMP) - } - - if o1 == 0 { - break - } - o2 = c.oprrr(p, p.As, int(p.Scond)) - o2 |= REGTMP & 15 - r := int(p.Reg) - if p.As == AMVN { - r = 0 - } else if r == 0 { - r = int(p.To.Reg) - } - o2 |= (uint32(r) & 15) << 16 - if p.To.Type != obj.TYPE_NONE { - o2 |= (uint32(p.To.Reg) & 15) << 12 - } - - case 14: /* movb/movbu/movh/movhu R,R */ - o1 = c.oprrr(p, ASLL, int(p.Scond)) - - if p.As == AMOVBU || p.As == AMOVHU { - o2 = c.oprrr(p, ASRL, int(p.Scond)) - } else { - o2 = c.oprrr(p, ASRA, int(p.Scond)) - } - - r := int(p.To.Reg) - o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12 - o2 |= uint32(r)&15 | (uint32(r)&15)<<12 - if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU { - o1 |= 24 << 7 - o2 |= 24 << 7 - } else { - o1 |= 16 << 7 - o2 |= 16 << 7 - } - - case 15: /* mul r,[r,]r */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - rf := int(p.From.Reg) - rt := int(p.To.Reg) - r := int(p.Reg) - if r == 0 { - r = rt - } - - o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 - - case 16: /* div r,[r,]r */ - o1 = 0xf << 28 - - o2 = 0 - - case 17: - o1 = c.oprrr(p, p.As, int(p.Scond)) - rf := int(p.From.Reg) - rt := int(p.To.Reg) - rt2 := int(p.To.Offset) - r := int(p.Reg) - o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12 - - case 18: /* BFX/BFXU/BFC/BFI */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - rt := int(p.To.Reg) - r := int(p.Reg) - if r == 0 { - r = rt - } else if p.As == ABFC { // only "BFC $width, $lsb, Reg" is accepted, p.Reg must be 0 - c.ctxt.Diag("illegal combination: %v", p) - } - if p.GetFrom3() == nil || p.GetFrom3().Type != obj.TYPE_CONST { - c.ctxt.Diag("%v: missing or wrong LSB", p) - break - } - lsb := p.GetFrom3().Offset - width := p.From.Offset - if lsb < 0 || lsb > 31 || width <= 0 || (lsb+width) > 32 { - c.ctxt.Diag("%v: wrong width or LSB", p) - } - switch p.As { - case ABFX, ABFXU: // (width-1) is encoded - o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(width-1)<<16 - case ABFC, ABFI: // MSB is encoded - o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(lsb+width-1)<<16 - default: - c.ctxt.Diag("illegal combination: %v", p) - } - - case 20: /* mov/movb/movbu R,O(R) */ - c.aclass(&p.To) - - r := int(p.To.Reg) - if r == 0 { - r = int(o.param) - } - o1 = c.osr(p.As, int(p.From.Reg), int32(c.instoffset), r, int(p.Scond)) - - case 21: /* mov/movbu O(R),R -> lr */ - c.aclass(&p.From) - - r := int(p.From.Reg) - if r == 0 { - r = int(o.param) - } - o1 = c.olr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond)) - if p.As != AMOVW { - o1 |= 1 << 22 - } - - case 22: /* XTAB R@>i, [R], R */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - switch p.From.Offset &^ 0xf { - // only 0/8/16/24 bits rotation is accepted - case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7: - o1 |= uint32(p.From.Offset) & 0xc0f - default: - c.ctxt.Diag("illegal shift: %v", p) - } - rt := p.To.Reg - r := p.Reg - if r == 0 { - r = rt - } - o1 |= (uint32(rt)&15)<<12 | (uint32(r)&15)<<16 - - case 23: /* MOVW/MOVB/MOVH R@>i, R */ - switch p.As { - case AMOVW: - o1 = c.mov(p) - case AMOVBU, AMOVBS, AMOVB, AMOVHU, AMOVHS, AMOVH: - o1 = c.movxt(p) - default: - c.ctxt.Diag("illegal combination: %v", p) - } - - case 30: /* mov/movb/movbu R,L(R) */ - o1 = c.omvl(p, &p.To, REGTMP) - - if o1 == 0 { - break - } - r := int(p.To.Reg) - if r == 0 { - r = int(o.param) - } - o2 = c.osrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond)) - if p.As != AMOVW { - o2 |= 1 << 22 - } - - case 31: /* mov/movbu L(R),R -> lr[b] */ - o1 = c.omvl(p, &p.From, REGTMP) - - if o1 == 0 { - break - } - r := int(p.From.Reg) - if r == 0 { - r = int(o.param) - } - o2 = c.olrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond)) - if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { - o2 |= 1 << 22 - } - - case 34: /* mov $lacon,R */ - o1 = c.omvl(p, &p.From, REGTMP) - - if o1 == 0 { - break - } - - o2 = c.oprrr(p, AADD, int(p.Scond)) - o2 |= REGTMP & 15 - r := int(p.From.Reg) - if r == 0 { - r = int(o.param) - } - o2 |= (uint32(r) & 15) << 16 - if p.To.Type != obj.TYPE_NONE { - o2 |= (uint32(p.To.Reg) & 15) << 12 - } - - case 35: /* mov PSR,R */ - o1 = 2<<23 | 0xf<<16 | 0<<0 - - o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - o1 |= (uint32(p.From.Reg) & 1) << 22 - o1 |= (uint32(p.To.Reg) & 15) << 12 - - case 36: /* mov R,PSR */ - o1 = 2<<23 | 0x2cf<<12 | 0<<4 - - if p.Scond&C_FBIT != 0 { - o1 ^= 0x010 << 12 - } - o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - o1 |= (uint32(p.To.Reg) & 1) << 22 - o1 |= (uint32(p.From.Reg) & 15) << 0 - - case 37: /* mov $con,PSR */ - c.aclass(&p.From) - - o1 = 2<<23 | 0x2cf<<12 | 0<<4 - if p.Scond&C_FBIT != 0 { - o1 ^= 0x010 << 12 - } - o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - o1 |= uint32(immrot(uint32(c.instoffset))) - o1 |= (uint32(p.To.Reg) & 1) << 22 - o1 |= (uint32(p.From.Reg) & 15) << 0 - - case 38, 39: - switch o.type_ { - case 38: /* movm $con,oreg -> stm */ - o1 = 0x4 << 25 - - o1 |= uint32(p.From.Offset & 0xffff) - o1 |= (uint32(p.To.Reg) & 15) << 16 - c.aclass(&p.To) - - case 39: /* movm oreg,$con -> ldm */ - o1 = 0x4<<25 | 1<<20 - - o1 |= uint32(p.To.Offset & 0xffff) - o1 |= (uint32(p.From.Reg) & 15) << 16 - c.aclass(&p.From) - } - - if c.instoffset != 0 { - c.ctxt.Diag("offset must be zero in MOVM; %v", p) - } - o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - if p.Scond&C_PBIT != 0 { - o1 |= 1 << 24 - } - if p.Scond&C_UBIT != 0 { - o1 |= 1 << 23 - } - if p.Scond&C_WBIT != 0 { - o1 |= 1 << 21 - } - - case 40: /* swp oreg,reg,reg */ - c.aclass(&p.From) - - if c.instoffset != 0 { - c.ctxt.Diag("offset must be zero in SWP") - } - o1 = 0x2<<23 | 0x9<<4 - if p.As != ASWPW { - o1 |= 1 << 22 - } - o1 |= (uint32(p.From.Reg) & 15) << 16 - o1 |= (uint32(p.Reg) & 15) << 0 - o1 |= (uint32(p.To.Reg) & 15) << 12 - o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - - case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ - o1 = 0xe8fd8000 - - case 50: /* floating point store */ - v := c.regoff(&p.To) - - r := int(p.To.Reg) - if r == 0 { - r = int(o.param) - } - o1 = c.ofsr(p.As, int(p.From.Reg), v, r, int(p.Scond), p) - - case 51: /* floating point load */ - v := c.regoff(&p.From) - - r := int(p.From.Reg) - if r == 0 { - r = int(o.param) - } - o1 = c.ofsr(p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20 - - case 52: /* floating point store, int32 offset UGLY */ - o1 = c.omvl(p, &p.To, REGTMP) - - if o1 == 0 { - break - } - r := int(p.To.Reg) - if r == 0 { - r = int(o.param) - } - o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 - o3 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p) - - case 53: /* floating point load, int32 offset UGLY */ - o1 = c.omvl(p, &p.From, REGTMP) - - if o1 == 0 { - break - } - r := int(p.From.Reg) - if r == 0 { - r = int(o.param) - } - o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 - o3 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 - - case 54: /* floating point arith */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - rf := int(p.From.Reg) - rt := int(p.To.Reg) - r := int(p.Reg) - if r == 0 { - switch p.As { - case AMULAD, AMULAF, AMULSF, AMULSD, ANMULAF, ANMULAD, ANMULSF, ANMULSD, - AFMULAD, AFMULAF, AFMULSF, AFMULSD, AFNMULAF, AFNMULAD, AFNMULSF, AFNMULSD: - c.ctxt.Diag("illegal combination: %v", p) - default: - r = rt - } - } - - o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 - - case 55: /* negf freg, freg */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - rf := int(p.From.Reg) - rt := int(p.To.Reg) - - o1 |= (uint32(rf)&15)<<0 | (uint32(rt)&15)<<12 - - case 56: /* move to FP[CS]R */ - o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xee1<<16 | 0xa1<<4 - - o1 |= (uint32(p.From.Reg) & 15) << 12 - - case 57: /* move from FP[CS]R */ - o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xef1<<16 | 0xa1<<4 - - o1 |= (uint32(p.To.Reg) & 15) << 12 - - case 58: /* movbu R,R */ - o1 = c.oprrr(p, AAND, int(p.Scond)) - - o1 |= uint32(immrot(0xff)) - rt := int(p.To.Reg) - r := int(p.From.Reg) - if p.To.Type == obj.TYPE_NONE { - rt = 0 - } - if r == 0 { - r = rt - } - o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 - - case 59: /* movw/bu R<<I(R),R -> ldr indexed */ - if p.From.Reg == 0 { - c.ctxt.Diag("source operand is not a memory address: %v", p) - break - } - if p.From.Offset&(1<<4) != 0 { - c.ctxt.Diag("bad shift in LDR") - break - } - o1 = c.olrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) - if p.As == AMOVBU { - o1 |= 1 << 22 - } - - case 60: /* movb R(R),R -> ldrsb indexed */ - if p.From.Reg == 0 { - c.ctxt.Diag("source operand is not a memory address: %v", p) - break - } - if p.From.Offset&(^0xf) != 0 { - c.ctxt.Diag("bad shift: %v", p) - break - } - o1 = c.olhrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) - switch p.As { - case AMOVB, AMOVBS: - o1 ^= 1<<5 | 1<<6 - case AMOVH, AMOVHS: - o1 ^= 1 << 6 - default: - } - if p.Scond&C_UBIT != 0 { - o1 &^= 1 << 23 - } - - case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ - if p.To.Reg == 0 { - c.ctxt.Diag("MOV to shifter operand") - } - o1 = c.osrr(int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond)) - if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU { - o1 |= 1 << 22 - } - - case 62: /* MOVH/MOVHS/MOVHU Reg, Reg<<0(Reg) -> strh */ - if p.To.Reg == 0 { - c.ctxt.Diag("MOV to shifter operand") - } - if p.To.Offset&(^0xf) != 0 { - c.ctxt.Diag("bad shift: %v", p) - } - o1 = c.olhrr(int(p.To.Offset), int(p.To.Reg), int(p.From.Reg), int(p.Scond)) - o1 ^= 1 << 20 - if p.Scond&C_UBIT != 0 { - o1 &^= 1 << 23 - } - - /* reloc ops */ - case 64: /* mov/movb/movbu R,addr */ - o1 = c.omvl(p, &p.To, REGTMP) - - if o1 == 0 { - break - } - o2 = c.osr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond)) - if o.flag&LPCREL != 0 { - o3 = o2 - o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 - } - - case 65: /* mov/movbu addr,R */ - o1 = c.omvl(p, &p.From, REGTMP) - - if o1 == 0 { - break - } - o2 = c.olr(0, REGTMP, int(p.To.Reg), int(p.Scond)) - if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { - o2 |= 1 << 22 - } - if o.flag&LPCREL != 0 { - o3 = o2 - o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 - } - - case 101: /* movw tlsvar,R, local exec*/ - o1 = c.omvl(p, &p.From, int(p.To.Reg)) - - case 102: /* movw tlsvar,R, initial exec*/ - o1 = c.omvl(p, &p.From, int(p.To.Reg)) - o2 = c.olrr(int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond)) - - case 103: /* word tlsvar, local exec */ - if p.To.Sym == nil { - c.ctxt.Diag("nil sym in tls %v", p) - } - if p.To.Offset != 0 { - c.ctxt.Diag("offset against tls var in %v", p) - } - // This case happens with words generated in the PC stream as part of - // the literal c.pool. - rel := obj.Addrel(c.cursym) - - rel.Off = int32(c.pc) - rel.Siz = 4 - rel.Sym = p.To.Sym - rel.Type = objabi.R_TLS_LE - o1 = 0 - - case 104: /* word tlsvar, initial exec */ - if p.To.Sym == nil { - c.ctxt.Diag("nil sym in tls %v", p) - } - if p.To.Offset != 0 { - c.ctxt.Diag("offset against tls var in %v", p) - } - rel := obj.Addrel(c.cursym) - rel.Off = int32(c.pc) - rel.Siz = 4 - rel.Sym = p.To.Sym - rel.Type = objabi.R_TLS_IE - rel.Add = c.pc - p.Rel.Pc - 8 - int64(rel.Siz) - - case 68: /* floating point store -> ADDR */ - o1 = c.omvl(p, &p.To, REGTMP) - - if o1 == 0 { - break - } - o2 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p) - if o.flag&LPCREL != 0 { - o3 = o2 - o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 - } - - case 69: /* floating point load <- ADDR */ - o1 = c.omvl(p, &p.From, REGTMP) - - if o1 == 0 { - break - } - o2 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 - if o.flag&LPCREL != 0 { - o3 = o2 - o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 - } - - /* ArmV4 ops: */ - case 70: /* movh/movhu R,O(R) -> strh */ - c.aclass(&p.To) - - r := int(p.To.Reg) - if r == 0 { - r = int(o.param) - } - o1 = c.oshr(int(p.From.Reg), int32(c.instoffset), r, int(p.Scond)) - - case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ - c.aclass(&p.From) - - r := int(p.From.Reg) - if r == 0 { - r = int(o.param) - } - o1 = c.olhr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond)) - if p.As == AMOVB || p.As == AMOVBS { - o1 ^= 1<<5 | 1<<6 - } else if p.As == AMOVH || p.As == AMOVHS { - o1 ^= (1 << 6) - } - - case 72: /* movh/movhu R,L(R) -> strh */ - o1 = c.omvl(p, &p.To, REGTMP) - - if o1 == 0 { - break - } - r := int(p.To.Reg) - if r == 0 { - r = int(o.param) - } - o2 = c.oshrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond)) - - case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ - o1 = c.omvl(p, &p.From, REGTMP) - - if o1 == 0 { - break - } - r := int(p.From.Reg) - if r == 0 { - r = int(o.param) - } - o2 = c.olhrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond)) - if p.As == AMOVB || p.As == AMOVBS { - o2 ^= 1<<5 | 1<<6 - } else if p.As == AMOVH || p.As == AMOVHS { - o2 ^= (1 << 6) - } - - case 74: /* bx $I */ - c.ctxt.Diag("ABX $I") - - case 75: /* bx O(R) */ - c.aclass(&p.To) - - if c.instoffset != 0 { - c.ctxt.Diag("non-zero offset in ABX") - } - - /* - o1 = c.oprrr(p, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR - o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0); // BX R - */ - // p->to.reg may be REGLINK - o1 = c.oprrr(p, AADD, int(p.Scond)) - - o1 |= uint32(immrot(uint32(c.instoffset))) - o1 |= (uint32(p.To.Reg) & 15) << 16 - o1 |= (REGTMP & 15) << 12 - o2 = c.oprrr(p, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR - o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15 // BX Rtmp - - case 76: /* bx O(R) when returning from fn*/ - c.ctxt.Diag("ABXRET") - - case 77: /* ldrex oreg,reg */ - c.aclass(&p.From) - - if c.instoffset != 0 { - c.ctxt.Diag("offset must be zero in LDREX") - } - o1 = 0x19<<20 | 0xf9f - o1 |= (uint32(p.From.Reg) & 15) << 16 - o1 |= (uint32(p.To.Reg) & 15) << 12 - o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - - case 78: /* strex reg,oreg,reg */ - c.aclass(&p.From) - - if c.instoffset != 0 { - c.ctxt.Diag("offset must be zero in STREX") - } - if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg { - c.ctxt.Diag("cannot use same register as both source and destination: %v", p) - } - o1 = 0x18<<20 | 0xf90 - o1 |= (uint32(p.From.Reg) & 15) << 16 - o1 |= (uint32(p.Reg) & 15) << 0 - o1 |= (uint32(p.To.Reg) & 15) << 12 - o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - - case 80: /* fmov zfcon,freg */ - if p.As == AMOVD { - o1 = 0xeeb00b00 // VMOV imm 64 - o2 = c.oprrr(p, ASUBD, int(p.Scond)) - } else { - o1 = 0x0eb00a00 // VMOV imm 32 - o2 = c.oprrr(p, ASUBF, int(p.Scond)) - } - - v := int32(0x70) // 1.0 - r := (int(p.To.Reg) & 15) << 0 - - // movf $1.0, r - o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - - o1 |= (uint32(r) & 15) << 12 - o1 |= (uint32(v) & 0xf) << 0 - o1 |= (uint32(v) & 0xf0) << 12 - - // subf r,r,r - o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12 - - case 81: /* fmov sfcon,freg */ - o1 = 0x0eb00a00 // VMOV imm 32 - if p.As == AMOVD { - o1 = 0xeeb00b00 // VMOV imm 64 - } - o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - o1 |= (uint32(p.To.Reg) & 15) << 12 - v := int32(c.chipfloat5(p.From.Val.(float64))) - o1 |= (uint32(v) & 0xf) << 0 - o1 |= (uint32(v) & 0xf0) << 12 - - case 82: /* fcmp freg,freg, */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0 - o2 = 0x0ef1fa10 // VMRS R15 - o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - - case 83: /* fcmp freg,, */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16 - o2 = 0x0ef1fa10 // VMRS R15 - o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - - case 84: /* movfw freg,freg - truncate float-to-fix */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - o1 |= (uint32(p.From.Reg) & 15) << 0 - o1 |= (uint32(p.To.Reg) & 15) << 12 - - case 85: /* movwf freg,freg - fix-to-float */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - o1 |= (uint32(p.From.Reg) & 15) << 0 - o1 |= (uint32(p.To.Reg) & 15) << 12 - - // macro for movfw freg,FTMP; movw FTMP,reg - case 86: /* movfw freg,reg - truncate float-to-fix */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - o1 |= (uint32(p.From.Reg) & 15) << 0 - o1 |= (FREGTMP & 15) << 12 - o2 = c.oprrr(p, -AMOVFW, int(p.Scond)) - o2 |= (FREGTMP & 15) << 16 - o2 |= (uint32(p.To.Reg) & 15) << 12 - - // macro for movw reg,FTMP; movwf FTMP,freg - case 87: /* movwf reg,freg - fix-to-float */ - o1 = c.oprrr(p, -AMOVWF, int(p.Scond)) - - o1 |= (uint32(p.From.Reg) & 15) << 12 - o1 |= (FREGTMP & 15) << 16 - o2 = c.oprrr(p, p.As, int(p.Scond)) - o2 |= (FREGTMP & 15) << 0 - o2 |= (uint32(p.To.Reg) & 15) << 12 - - case 88: /* movw reg,freg */ - o1 = c.oprrr(p, -AMOVWF, int(p.Scond)) - - o1 |= (uint32(p.From.Reg) & 15) << 12 - o1 |= (uint32(p.To.Reg) & 15) << 16 - - case 89: /* movw freg,reg */ - o1 = c.oprrr(p, -AMOVFW, int(p.Scond)) - - o1 |= (uint32(p.From.Reg) & 15) << 16 - o1 |= (uint32(p.To.Reg) & 15) << 12 - - case 91: /* ldrexd oreg,reg */ - c.aclass(&p.From) - - if c.instoffset != 0 { - c.ctxt.Diag("offset must be zero in LDREX") - } - o1 = 0x1b<<20 | 0xf9f - o1 |= (uint32(p.From.Reg) & 15) << 16 - o1 |= (uint32(p.To.Reg) & 15) << 12 - o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - - case 92: /* strexd reg,oreg,reg */ - c.aclass(&p.From) - - if c.instoffset != 0 { - c.ctxt.Diag("offset must be zero in STREX") - } - if p.Reg&1 != 0 { - c.ctxt.Diag("source register must be even in STREXD: %v", p) - } - if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg || p.To.Reg == p.Reg+1 { - c.ctxt.Diag("cannot use same register as both source and destination: %v", p) - } - o1 = 0x1a<<20 | 0xf90 - o1 |= (uint32(p.From.Reg) & 15) << 16 - o1 |= (uint32(p.Reg) & 15) << 0 - o1 |= (uint32(p.To.Reg) & 15) << 12 - o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - - case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ - o1 = c.omvl(p, &p.From, REGTMP) - - if o1 == 0 { - break - } - o2 = c.olhr(0, REGTMP, int(p.To.Reg), int(p.Scond)) - if p.As == AMOVB || p.As == AMOVBS { - o2 ^= 1<<5 | 1<<6 - } else if p.As == AMOVH || p.As == AMOVHS { - o2 ^= (1 << 6) - } - if o.flag&LPCREL != 0 { - o3 = o2 - o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 - } - - case 94: /* movh/movhu R,addr -> strh */ - o1 = c.omvl(p, &p.To, REGTMP) - - if o1 == 0 { - break - } - o2 = c.oshr(int(p.From.Reg), 0, REGTMP, int(p.Scond)) - if o.flag&LPCREL != 0 { - o3 = o2 - o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 - } - - case 95: /* PLD off(reg) */ - o1 = 0xf5d0f000 - - o1 |= (uint32(p.From.Reg) & 15) << 16 - if p.From.Offset < 0 { - o1 &^= (1 << 23) - o1 |= uint32((-p.From.Offset) & 0xfff) - } else { - o1 |= uint32(p.From.Offset & 0xfff) - } - - // This is supposed to be something that stops execution. - // It's not supposed to be reached, ever, but if it is, we'd - // like to be able to tell how we got there. Assemble as - // 0xf7fabcfd which is guaranteed to raise undefined instruction - // exception. - case 96: /* UNDEF */ - o1 = 0xf7fabcfd - - case 97: /* CLZ Rm, Rd */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - o1 |= (uint32(p.To.Reg) & 15) << 12 - o1 |= (uint32(p.From.Reg) & 15) << 0 - - case 98: /* MULW{T,B} Rs, Rm, Rd */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - o1 |= (uint32(p.To.Reg) & 15) << 16 - o1 |= (uint32(p.From.Reg) & 15) << 8 - o1 |= (uint32(p.Reg) & 15) << 0 - - case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - - o1 |= (uint32(p.To.Reg) & 15) << 16 - o1 |= (uint32(p.From.Reg) & 15) << 8 - o1 |= (uint32(p.Reg) & 15) << 0 - o1 |= uint32((p.To.Offset & 15) << 12) - - case 105: /* divhw r,[r,]r */ - o1 = c.oprrr(p, p.As, int(p.Scond)) - rf := int(p.From.Reg) - rt := int(p.To.Reg) - r := int(p.Reg) - if r == 0 { - r = rt - } - o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 - - case 110: /* dmb [mbop | $con] */ - o1 = 0xf57ff050 - mbop := uint32(0) - - switch c.aclass(&p.From) { - case C_SPR: - for _, f := range mbOp { - if f.reg == p.From.Reg { - mbop = f.enc - break - } - } - case C_RCON: - for _, f := range mbOp { - enc := uint32(c.instoffset) - if f.enc == enc { - mbop = enc - break - } - } - case C_NONE: - mbop = 0xf - } - - if mbop == 0 { - c.ctxt.Diag("illegal mb option:\n%v", p) - } - o1 |= mbop - } - - out[0] = o1 - out[1] = o2 - out[2] = o3 - out[3] = o4 - out[4] = o5 - out[5] = o6 -} - -func (c *ctxt5) movxt(p *obj.Prog) uint32 { - o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - switch p.As { - case AMOVB, AMOVBS: - o1 |= 0x6af<<16 | 0x7<<4 - case AMOVH, AMOVHS: - o1 |= 0x6bf<<16 | 0x7<<4 - case AMOVBU: - o1 |= 0x6ef<<16 | 0x7<<4 - case AMOVHU: - o1 |= 0x6ff<<16 | 0x7<<4 - default: - c.ctxt.Diag("illegal combination: %v", p) - } - switch p.From.Offset &^ 0xf { - // only 0/8/16/24 bits rotation is accepted - case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7: - o1 |= uint32(p.From.Offset) & 0xc0f - default: - c.ctxt.Diag("illegal shift: %v", p) - } - o1 |= (uint32(p.To.Reg) & 15) << 12 - return o1 -} - -func (c *ctxt5) mov(p *obj.Prog) uint32 { - c.aclass(&p.From) - o1 := c.oprrr(p, p.As, int(p.Scond)) - o1 |= uint32(p.From.Offset) - rt := int(p.To.Reg) - if p.To.Type == obj.TYPE_NONE { - rt = 0 - } - r := int(p.Reg) - if p.As == AMOVW || p.As == AMVN { - r = 0 - } else if r == 0 { - r = rt - } - o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 - return o1 -} - -func (c *ctxt5) oprrr(p *obj.Prog, a obj.As, sc int) uint32 { - o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 - if sc&C_SBIT != 0 { - o |= 1 << 20 - } - switch a { - case ADIVHW: - return o | 0x71<<20 | 0xf<<12 | 0x1<<4 - case ADIVUHW: - return o | 0x73<<20 | 0xf<<12 | 0x1<<4 - case AMMUL: - return o | 0x75<<20 | 0xf<<12 | 0x1<<4 - case AMULS: - return o | 0x6<<20 | 0x9<<4 - case AMMULA: - return o | 0x75<<20 | 0x1<<4 - case AMMULS: - return o | 0x75<<20 | 0xd<<4 - case AMULU, AMUL: - return o | 0x0<<21 | 0x9<<4 - case AMULA: - return o | 0x1<<21 | 0x9<<4 - case AMULLU: - return o | 0x4<<21 | 0x9<<4 - case AMULL: - return o | 0x6<<21 | 0x9<<4 - case AMULALU: - return o | 0x5<<21 | 0x9<<4 - case AMULAL: - return o | 0x7<<21 | 0x9<<4 - case AAND: - return o | 0x0<<21 - case AEOR: - return o | 0x1<<21 - case ASUB: - return o | 0x2<<21 - case ARSB: - return o | 0x3<<21 - case AADD: - return o | 0x4<<21 - case AADC: - return o | 0x5<<21 - case ASBC: - return o | 0x6<<21 - case ARSC: - return o | 0x7<<21 - case ATST: - return o | 0x8<<21 | 1<<20 - case ATEQ: - return o | 0x9<<21 | 1<<20 - case ACMP: - return o | 0xa<<21 | 1<<20 - case ACMN: - return o | 0xb<<21 | 1<<20 - case AORR: - return o | 0xc<<21 - - case AMOVB, AMOVH, AMOVW: - if sc&(C_PBIT|C_WBIT) != 0 { - c.ctxt.Diag("invalid .P/.W suffix: %v", p) - } - return o | 0xd<<21 - case ABIC: - return o | 0xe<<21 - case AMVN: - return o | 0xf<<21 - case ASLL: - return o | 0xd<<21 | 0<<5 - case ASRL: - return o | 0xd<<21 | 1<<5 - case ASRA: - return o | 0xd<<21 | 2<<5 - case ASWI: - return o | 0xf<<24 - - case AADDD: - return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4 - case AADDF: - return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4 - case ASUBD: - return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4 - case ASUBF: - return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4 - case AMULD: - return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4 - case AMULF: - return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4 - case ANMULD: - return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0x4<<4 - case ANMULF: - return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0x4<<4 - case AMULAD: - return o | 0xe<<24 | 0xb<<8 - case AMULAF: - return o | 0xe<<24 | 0xa<<8 - case AMULSD: - return o | 0xe<<24 | 0xb<<8 | 0x4<<4 - case AMULSF: - return o | 0xe<<24 | 0xa<<8 | 0x4<<4 - case ANMULAD: - return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 0x4<<4 - case ANMULAF: - return o | 0xe<<24 | 0x1<<20 | 0xa<<8 | 0x4<<4 - case ANMULSD: - return o | 0xe<<24 | 0x1<<20 | 0xb<<8 - case ANMULSF: - return o | 0xe<<24 | 0x1<<20 | 0xa<<8 - case AFMULAD: - return o | 0xe<<24 | 0xa<<20 | 0xb<<8 - case AFMULAF: - return o | 0xe<<24 | 0xa<<20 | 0xa<<8 - case AFMULSD: - return o | 0xe<<24 | 0xa<<20 | 0xb<<8 | 0x4<<4 - case AFMULSF: - return o | 0xe<<24 | 0xa<<20 | 0xa<<8 | 0x4<<4 - case AFNMULAD: - return o | 0xe<<24 | 0x9<<20 | 0xb<<8 | 0x4<<4 - case AFNMULAF: - return o | 0xe<<24 | 0x9<<20 | 0xa<<8 | 0x4<<4 - case AFNMULSD: - return o | 0xe<<24 | 0x9<<20 | 0xb<<8 - case AFNMULSF: - return o | 0xe<<24 | 0x9<<20 | 0xa<<8 - case ADIVD: - return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4 - case ADIVF: - return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4 - case ASQRTD: - return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4 - case ASQRTF: - return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4 - case AABSD: - return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4 - case AABSF: - return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4 - case ANEGD: - return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0x4<<4 - case ANEGF: - return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0x4<<4 - case ACMPD: - return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4 - case ACMPF: - return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4 - - case AMOVF: - return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4 - case AMOVD: - return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4 - - case AMOVDF: - return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof - case AMOVFD: - return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof - - case AMOVWF: - if sc&C_UBIT == 0 { - o |= 1 << 7 /* signed */ - } - return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double - - case AMOVWD: - if sc&C_UBIT == 0 { - o |= 1 << 7 /* signed */ - } - return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double - - case AMOVFW: - if sc&C_UBIT == 0 { - o |= 1 << 16 /* signed */ - } - return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc - - case AMOVDW: - if sc&C_UBIT == 0 { - o |= 1 << 16 /* signed */ - } - return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc - - case -AMOVWF: // copy WtoF - return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4 - - case -AMOVFW: // copy FtoW - return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4 - - case -ACMP: // cmp imm - return o | 0x3<<24 | 0x5<<20 - - case ABFX: - return o | 0x3d<<21 | 0x5<<4 - - case ABFXU: - return o | 0x3f<<21 | 0x5<<4 - - case ABFC: - return o | 0x3e<<21 | 0x1f - - case ABFI: - return o | 0x3e<<21 | 0x1<<4 - - case AXTAB: - return o | 0x6a<<20 | 0x7<<4 - - case AXTAH: - return o | 0x6b<<20 | 0x7<<4 - - case AXTABU: - return o | 0x6e<<20 | 0x7<<4 - - case AXTAHU: - return o | 0x6f<<20 | 0x7<<4 - - // CLZ doesn't support .nil - case ACLZ: - return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4 - - case AREV: - return o&(0xf<<28) | 0x6bf<<16 | 0xf3<<4 - - case AREV16: - return o&(0xf<<28) | 0x6bf<<16 | 0xfb<<4 - - case AREVSH: - return o&(0xf<<28) | 0x6ff<<16 | 0xfb<<4 - - case ARBIT: - return o&(0xf<<28) | 0x6ff<<16 | 0xf3<<4 - - case AMULWT: - return o&(0xf<<28) | 0x12<<20 | 0xe<<4 - - case AMULWB: - return o&(0xf<<28) | 0x12<<20 | 0xa<<4 - - case AMULBB: - return o&(0xf<<28) | 0x16<<20 | 0x8<<4 - - case AMULAWT: - return o&(0xf<<28) | 0x12<<20 | 0xc<<4 - - case AMULAWB: - return o&(0xf<<28) | 0x12<<20 | 0x8<<4 - - case AMULABB: - return o&(0xf<<28) | 0x10<<20 | 0x8<<4 - - case ABL: // BLX REG - return o&(0xf<<28) | 0x12fff3<<4 - } - - c.ctxt.Diag("%v: bad rrr %d", p, a) - return 0 -} - -func (c *ctxt5) opbra(p *obj.Prog, a obj.As, sc int) uint32 { - sc &= C_SCOND - sc ^= C_SCOND_XOR - if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY { - return uint32(sc)<<28 | 0x5<<25 | 0x1<<24 - } - if sc != 0xe { - c.ctxt.Diag("%v: .COND on bcond instruction", p) - } - switch a { - case ABEQ: - return 0x0<<28 | 0x5<<25 - case ABNE: - return 0x1<<28 | 0x5<<25 - case ABCS: - return 0x2<<28 | 0x5<<25 - case ABHS: - return 0x2<<28 | 0x5<<25 - case ABCC: - return 0x3<<28 | 0x5<<25 - case ABLO: - return 0x3<<28 | 0x5<<25 - case ABMI: - return 0x4<<28 | 0x5<<25 - case ABPL: - return 0x5<<28 | 0x5<<25 - case ABVS: - return 0x6<<28 | 0x5<<25 - case ABVC: - return 0x7<<28 | 0x5<<25 - case ABHI: - return 0x8<<28 | 0x5<<25 - case ABLS: - return 0x9<<28 | 0x5<<25 - case ABGE: - return 0xa<<28 | 0x5<<25 - case ABLT: - return 0xb<<28 | 0x5<<25 - case ABGT: - return 0xc<<28 | 0x5<<25 - case ABLE: - return 0xd<<28 | 0x5<<25 - case AB: - return 0xe<<28 | 0x5<<25 - } - - c.ctxt.Diag("%v: bad bra %v", p, a) - return 0 -} - -func (c *ctxt5) olr(v int32, b int, r int, sc int) uint32 { - o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 - if sc&C_PBIT == 0 { - o |= 1 << 24 - } - if sc&C_UBIT == 0 { - o |= 1 << 23 - } - if sc&C_WBIT != 0 { - o |= 1 << 21 - } - o |= 1<<26 | 1<<20 - if v < 0 { - if sc&C_UBIT != 0 { - c.ctxt.Diag(".U on neg offset") - } - v = -v - o ^= 1 << 23 - } - - if v >= 1<<12 || v < 0 { - c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp) - } - o |= uint32(v) - o |= (uint32(b) & 15) << 16 - o |= (uint32(r) & 15) << 12 - return o -} - -func (c *ctxt5) olhr(v int32, b int, r int, sc int) uint32 { - o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 - if sc&C_PBIT == 0 { - o |= 1 << 24 - } - if sc&C_WBIT != 0 { - o |= 1 << 21 - } - o |= 1<<23 | 1<<20 | 0xb<<4 - if v < 0 { - v = -v - o ^= 1 << 23 - } - - if v >= 1<<8 || v < 0 { - c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp) - } - o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22 - o |= (uint32(b) & 15) << 16 - o |= (uint32(r) & 15) << 12 - return o -} - -func (c *ctxt5) osr(a obj.As, r int, v int32, b int, sc int) uint32 { - o := c.olr(v, b, r, sc) ^ (1 << 20) - if a != AMOVW { - o |= 1 << 22 - } - return o -} - -func (c *ctxt5) oshr(r int, v int32, b int, sc int) uint32 { - o := c.olhr(v, b, r, sc) ^ (1 << 20) - return o -} - -func (c *ctxt5) osrr(r int, i int, b int, sc int) uint32 { - return c.olr(int32(i), b, r, sc) ^ (1<<25 | 1<<20) -} - -func (c *ctxt5) oshrr(r int, i int, b int, sc int) uint32 { - return c.olhr(int32(i), b, r, sc) ^ (1<<22 | 1<<20) -} - -func (c *ctxt5) olrr(i int, b int, r int, sc int) uint32 { - return c.olr(int32(i), b, r, sc) ^ (1 << 25) -} - -func (c *ctxt5) olhrr(i int, b int, r int, sc int) uint32 { - return c.olhr(int32(i), b, r, sc) ^ (1 << 22) -} - -func (c *ctxt5) ofsr(a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 { - o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 - if sc&C_PBIT == 0 { - o |= 1 << 24 - } - if sc&C_WBIT != 0 { - o |= 1 << 21 - } - o |= 6<<25 | 1<<24 | 1<<23 | 10<<8 - if v < 0 { - v = -v - o ^= 1 << 23 - } - - if v&3 != 0 { - c.ctxt.Diag("odd offset for floating point op: %d\n%v", v, p) - } else if v >= 1<<10 || v < 0 { - c.ctxt.Diag("literal span too large: %d\n%v", v, p) - } - o |= (uint32(v) >> 2) & 0xFF - o |= (uint32(b) & 15) << 16 - o |= (uint32(r) & 15) << 12 - - switch a { - default: - c.ctxt.Diag("bad fst %v", a) - fallthrough - - case AMOVD: - o |= 1 << 8 - fallthrough - - case AMOVF: - break - } - - return o -} - -// MOVW $"lower 16-bit", Reg -func (c *ctxt5) omvs(p *obj.Prog, a *obj.Addr, dr int) uint32 { - o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 - o1 |= 0x30 << 20 - o1 |= (uint32(dr) & 15) << 12 - o1 |= uint32(a.Offset) & 0x0fff - o1 |= (uint32(a.Offset) & 0xf000) << 4 - return o1 -} - -// MVN $C_NCON, Reg -> MOVW $C_RCON, Reg -func (c *ctxt5) omvr(p *obj.Prog, a *obj.Addr, dr int) uint32 { - o1 := c.oprrr(p, AMOVW, int(p.Scond)) - o1 |= (uint32(dr) & 15) << 12 - v := immrot(^uint32(a.Offset)) - if v == 0 { - c.ctxt.Diag("%v: missing literal", p) - return 0 - } - o1 |= uint32(v) - return o1 -} - -func (c *ctxt5) omvl(p *obj.Prog, a *obj.Addr, dr int) uint32 { - var o1 uint32 - if p.Pool == nil { - c.aclass(a) - v := immrot(^uint32(c.instoffset)) - if v == 0 { - c.ctxt.Diag("%v: missing literal", p) - return 0 - } - - o1 = c.oprrr(p, AMVN, int(p.Scond)&C_SCOND) - o1 |= uint32(v) - o1 |= (uint32(dr) & 15) << 12 - } else { - v := int32(p.Pool.Pc - p.Pc - 8) - o1 = c.olr(v, REGPC, dr, int(p.Scond)&C_SCOND) - } - - return o1 -} - -func (c *ctxt5) chipzero5(e float64) int { - // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. - if objabi.GOARM < 7 || math.Float64bits(e) != 0 { - return -1 - } - return 0 -} - -func (c *ctxt5) chipfloat5(e float64) int { - // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. - if objabi.GOARM < 7 { - return -1 - } - - ei := math.Float64bits(e) - l := uint32(ei) - h := uint32(ei >> 32) - - if l != 0 || h&0xffff != 0 { - return -1 - } - h1 := h & 0x7fc00000 - if h1 != 0x40000000 && h1 != 0x3fc00000 { - return -1 - } - n := 0 - - // sign bit (a) - if h&0x80000000 != 0 { - n |= 1 << 7 - } - - // exp sign bit (b) - if h1 == 0x3fc00000 { - n |= 1 << 6 - } - - // rest of exp and mantissa (cd-efgh) - n |= int((h >> 16) & 0x3f) - - //print("match %.8lux %.8lux %d\n", l, h, n); - return n -} - -func nocache(p *obj.Prog) { - p.Optab = 0 - p.From.Class = 0 - if p.GetFrom3() != nil { - p.GetFrom3().Class = 0 - } - p.To.Class = 0 -} |