asm5.go (80187B)
1 // Inferno utils/5l/span.c 2 // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/span.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 package arm 32 33 import ( 34 "github.com/twitchyliquid64/golang-asm/obj" 35 "github.com/twitchyliquid64/golang-asm/objabi" 36 "fmt" 37 "log" 38 "math" 39 "sort" 40 ) 41 42 // ctxt5 holds state while assembling a single function. 43 // Each function gets a fresh ctxt5. 44 // This allows for multiple functions to be safely concurrently assembled. 45 type ctxt5 struct { 46 ctxt *obj.Link 47 newprog obj.ProgAlloc 48 cursym *obj.LSym 49 printp *obj.Prog 50 blitrl *obj.Prog 51 elitrl *obj.Prog 52 autosize int64 53 instoffset int64 54 pc int64 55 pool struct { 56 start uint32 57 size uint32 58 extra uint32 59 } 60 } 61 62 type Optab struct { 63 as obj.As 64 a1 uint8 65 a2 int8 66 a3 uint8 67 type_ uint8 68 size int8 69 param int16 70 flag int8 71 pcrelsiz uint8 72 scond uint8 // optional flags accepted by the instruction 73 } 74 75 type Opcross [32][2][32]uint8 76 77 const ( 78 LFROM = 1 << 0 79 LTO = 1 << 1 80 LPOOL = 1 << 2 81 LPCREL = 1 << 3 82 ) 83 84 var optab = []Optab{ 85 /* struct Optab: 86 OPCODE, from, prog->reg, to, type, size, param, flag, extra data size, optional suffix */ 87 {obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0, 0}, 88 {AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT}, 89 {AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, 90 {AAND, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT}, 91 {AAND, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, 92 {AORR, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0, C_SBIT}, 93 {AORR, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, 94 {AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, 95 {AMVN, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, C_SBIT}, 96 {ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0, 0}, 97 {AADD, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT}, 98 {AADD, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT}, 99 {AAND, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT}, 100 {AAND, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT}, 101 {AORR, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0, C_SBIT}, 102 {AORR, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, C_SBIT}, 103 {AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, 0}, 104 {AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0, 0}, 105 {ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0, 0, 0, 0}, 106 {AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT}, 107 {AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, 108 {AAND, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT}, 109 {AAND, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, 110 {AORR, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0, C_SBIT}, 111 {AORR, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, 112 {AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0, C_SBIT}, 113 {ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0, 0}, 114 {AMOVW, C_RACON, C_NONE, C_REG, 4, 4, REGSP, 0, 0, C_SBIT}, 115 {AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL, 0, 0}, 116 {ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, 117 {ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0, 0, 0, 0}, 118 {ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, 119 {ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // prediction hinted form, hint ignored 120 {AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL, 0, 0}, 121 {ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0, 0, 0, 0}, 122 {ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0, 0, 0, 0}, 123 {ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0, 0, 0, 0}, 124 {ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0, 0, 0, 0}, 125 {ASLL, C_RCON, C_REG, C_REG, 8, 4, 0, 0, 0, C_SBIT}, 126 {ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0, 0, 0, C_SBIT}, 127 {ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0, C_SBIT}, 128 {ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0, C_SBIT}, 129 {ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0, 0}, 130 {ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0, 0, 0, 0}, 131 {AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0, 0, 0, 0}, 132 {AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0, 0, 0, 0}, 133 {AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0, 0, 0, 0}, 134 {AWORD, C_NONE, C_NONE, C_TLS_LE, 103, 4, 0, 0, 0, 0}, 135 {AWORD, C_NONE, C_NONE, C_TLS_IE, 104, 4, 0, 0, 0, 0}, 136 {AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0}, 137 {AMOVW, C_SCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0}, 138 {AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0, 0}, 139 {AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4, 0}, 140 {AMVN, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0, 0}, 141 {AADD, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 142 {AADD, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 143 {AAND, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 144 {AAND, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 145 {AORR, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 146 {AORR, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 147 {ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0, 0, 0, 0}, 148 {AADD, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 149 {AADD, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 150 {AAND, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 151 {AAND, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 152 {AORR, C_SCON, C_REG, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 153 {AORR, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, C_SBIT}, 154 {AMVN, C_SCON, C_NONE, C_REG, 13, 8, 0, 0, 0, 0}, 155 {ACMP, C_SCON, C_REG, C_NONE, 13, 8, 0, 0, 0, 0}, 156 {AADD, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0, 0}, 157 {AADD, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0, 0}, 158 {AORR, C_RCON2A, C_REG, C_REG, 106, 8, 0, 0, 0, 0}, 159 {AORR, C_RCON2A, C_NONE, C_REG, 106, 8, 0, 0, 0, 0}, 160 {AADD, C_RCON2S, C_REG, C_REG, 107, 8, 0, 0, 0, 0}, 161 {AADD, C_RCON2S, C_NONE, C_REG, 107, 8, 0, 0, 0, 0}, 162 {AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, 163 {AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, 164 {AAND, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, 165 {AAND, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, 166 {AORR, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, 167 {AORR, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, C_SBIT}, 168 {AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0, 0}, 169 {ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0, 0}, 170 {AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, 0}, 171 {AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0}, 172 {AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0, 0, 0, 0}, 173 {AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0, 0}, 174 {AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0}, 175 {AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0, 0}, 176 {AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0, C_SBIT}, 177 {AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0, C_SBIT}, 178 {ADIV, C_REG, C_REG, C_REG, 16, 4, 0, 0, 0, 0}, 179 {ADIV, C_REG, C_NONE, C_REG, 16, 4, 0, 0, 0, 0}, 180 {ADIVHW, C_REG, C_REG, C_REG, 105, 4, 0, 0, 0, 0}, 181 {ADIVHW, C_REG, C_NONE, C_REG, 105, 4, 0, 0, 0, 0}, 182 {AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0, C_SBIT}, 183 {ABFX, C_LCON, C_REG, C_REG, 18, 4, 0, 0, 0, 0}, // width in From, LSB in From3 184 {ABFX, C_LCON, C_NONE, C_REG, 18, 4, 0, 0, 0, 0}, // width in From, LSB in From3 185 {AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 186 {AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 187 {AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 188 {AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 189 {AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 190 {AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 191 {AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 192 {AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 193 {AMOVW, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 194 {AMOVW, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 195 {AMOVBU, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 196 {AMOVBU, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 197 {AXTAB, C_SHIFT, C_REG, C_REG, 22, 4, 0, 0, 0, 0}, 198 {AXTAB, C_SHIFT, C_NONE, C_REG, 22, 4, 0, 0, 0, 0}, 199 {AMOVW, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, C_SBIT}, 200 {AMOVB, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, 201 {AMOVBS, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, 202 {AMOVBU, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, 203 {AMOVH, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, 204 {AMOVHS, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, 205 {AMOVHU, C_SHIFT, C_NONE, C_REG, 23, 4, 0, 0, 0, 0}, 206 {AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 207 {AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 208 {AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 209 {AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 210 {AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 211 {AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 212 {AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 213 {AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 214 {AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 215 {AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 216 {AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 217 {AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 218 {AMOVW, C_TLS_LE, C_NONE, C_REG, 101, 4, 0, LFROM, 0, 0}, 219 {AMOVW, C_TLS_IE, C_NONE, C_REG, 102, 8, 0, LFROM, 0, 0}, 220 {AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 221 {AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 222 {AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 223 {AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 224 {AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 225 {AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 226 {AMOVW, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0, C_SBIT}, 227 {AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0, 0, 0, 0}, 228 {AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0, 0, 0, 0}, 229 {AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0, 0, 0, 0}, 230 {AMOVM, C_REGLIST, C_NONE, C_SOREG, 38, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 231 {AMOVM, C_SOREG, C_NONE, C_REGLIST, 39, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 232 {ASWPW, C_SOREG, C_REG, C_REG, 40, 4, 0, 0, 0, 0}, 233 {ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0, 0}, 234 {AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 235 {AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 236 {AMOVF, C_FAUTO, C_NONE, C_FREG, 51, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 237 {AMOVF, C_FOREG, C_NONE, C_FREG, 51, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 238 {AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 239 {AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 240 {AMOVF, C_LAUTO, C_NONE, C_FREG, 53, 12, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 241 {AMOVF, C_LOREG, C_NONE, C_FREG, 53, 12, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 242 {AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 243 {AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 244 {AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0, 0}, 245 {AADDF, C_FREG, C_FREG, C_FREG, 54, 4, 0, 0, 0, 0}, 246 {AMOVF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0, 0}, 247 {ANEGF, C_FREG, C_NONE, C_FREG, 55, 4, 0, 0, 0, 0}, 248 {AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0, 0, 0, 0}, 249 {AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0, 0, 0, 0}, 250 {AMOVW, C_SHIFTADDR, C_NONE, C_REG, 59, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 251 {AMOVBU, C_SHIFTADDR, C_NONE, C_REG, 59, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 252 {AMOVB, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 253 {AMOVBS, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 254 {AMOVH, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 255 {AMOVHS, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 256 {AMOVHU, C_SHIFTADDR, C_NONE, C_REG, 60, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 257 {AMOVW, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 258 {AMOVB, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 259 {AMOVBS, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 260 {AMOVBU, C_REG, C_NONE, C_SHIFTADDR, 61, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 261 {AMOVH, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 262 {AMOVHS, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 263 {AMOVHU, C_REG, C_NONE, C_SHIFTADDR, 62, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 264 {AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 265 {AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 266 {AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 267 {AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 268 {AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 269 {AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 270 {AMOVB, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 271 {AMOVB, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 272 {AMOVBS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 273 {AMOVBS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 274 {AMOVH, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 275 {AMOVH, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 276 {AMOVHS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 277 {AMOVHS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 278 {AMOVHU, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 279 {AMOVHU, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0, C_PBIT | C_WBIT | C_UBIT}, 280 {AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 281 {AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 282 {AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 283 {AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 284 {AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 285 {AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 286 {AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 287 {AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0, C_PBIT | C_WBIT | C_UBIT}, 288 {AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 289 {AMOVB, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 290 {AMOVB, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 291 {AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 292 {AMOVBS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 293 {AMOVBS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 294 {AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 295 {AMOVH, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 296 {AMOVH, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 297 {AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 298 {AMOVHS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 299 {AMOVHS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 300 {AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 301 {AMOVHU, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 302 {AMOVHU, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0, C_PBIT | C_WBIT | C_UBIT}, 303 {AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4, C_PBIT | C_WBIT | C_UBIT}, 304 {ALDREX, C_SOREG, C_NONE, C_REG, 77, 4, 0, 0, 0, 0}, 305 {ASTREX, C_SOREG, C_REG, C_REG, 78, 4, 0, 0, 0, 0}, 306 {ADMB, C_NONE, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0}, 307 {ADMB, C_LCON, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0}, 308 {ADMB, C_SPR, C_NONE, C_NONE, 110, 4, 0, 0, 0, 0}, 309 {AMOVF, C_ZFCON, C_NONE, C_FREG, 80, 8, 0, 0, 0, 0}, 310 {AMOVF, C_SFCON, C_NONE, C_FREG, 81, 4, 0, 0, 0, 0}, 311 {ACMPF, C_FREG, C_FREG, C_NONE, 82, 8, 0, 0, 0, 0}, 312 {ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0, 0, 0, 0}, 313 {AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0, 0, 0, C_UBIT}, 314 {AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0, 0, 0, C_UBIT}, 315 {AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0, 0, 0, C_UBIT}, 316 {AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0, 0, 0, C_UBIT}, 317 {AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0, 0, 0, 0}, 318 {AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0, 0, 0, 0}, 319 {ALDREXD, C_SOREG, C_NONE, C_REG, 91, 4, 0, 0, 0, 0}, 320 {ASTREXD, C_SOREG, C_REG, C_REG, 92, 4, 0, 0, 0, 0}, 321 {APLD, C_SOREG, C_NONE, C_NONE, 95, 4, 0, 0, 0, 0}, 322 {obj.AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0, 0, 0, 0}, 323 {ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0, 0}, 324 {AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0, 0}, 325 {AMULA, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0, C_SBIT}, 326 {AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0, 0}, 327 {obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0, 0}, 328 {obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0, 0}, 329 {obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, 330 {obj.ANOP, C_LCON, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, // nop variants, see #40689 331 {obj.ANOP, C_REG, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, 332 {obj.ANOP, C_FREG, C_NONE, C_NONE, 0, 0, 0, 0, 0, 0}, 333 {obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // same as ABL 334 {obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0, 0}, // same as ABL 335 {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0, 0}, 336 } 337 338 var mbOp = []struct { 339 reg int16 340 enc uint32 341 }{ 342 {REG_MB_SY, 15}, 343 {REG_MB_ST, 14}, 344 {REG_MB_ISH, 11}, 345 {REG_MB_ISHST, 10}, 346 {REG_MB_NSH, 7}, 347 {REG_MB_NSHST, 6}, 348 {REG_MB_OSH, 3}, 349 {REG_MB_OSHST, 2}, 350 } 351 352 var oprange [ALAST & obj.AMask][]Optab 353 354 var xcmp [C_GOK + 1][C_GOK + 1]bool 355 356 var ( 357 deferreturn *obj.LSym 358 symdiv *obj.LSym 359 symdivu *obj.LSym 360 symmod *obj.LSym 361 symmodu *obj.LSym 362 ) 363 364 // Note about encoding: Prog.scond holds the condition encoding, 365 // but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0. 366 // The code that shifts the value << 28 has the responsibility 367 // for XORing with C_SCOND_XOR too. 368 369 func checkSuffix(c *ctxt5, p *obj.Prog, o *Optab) { 370 if p.Scond&C_SBIT != 0 && o.scond&C_SBIT == 0 { 371 c.ctxt.Diag("invalid .S suffix: %v", p) 372 } 373 if p.Scond&C_PBIT != 0 && o.scond&C_PBIT == 0 { 374 c.ctxt.Diag("invalid .P suffix: %v", p) 375 } 376 if p.Scond&C_WBIT != 0 && o.scond&C_WBIT == 0 { 377 c.ctxt.Diag("invalid .W suffix: %v", p) 378 } 379 if p.Scond&C_UBIT != 0 && o.scond&C_UBIT == 0 { 380 c.ctxt.Diag("invalid .U suffix: %v", p) 381 } 382 } 383 384 func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { 385 if ctxt.Retpoline { 386 ctxt.Diag("-spectre=ret not supported on arm") 387 ctxt.Retpoline = false // don't keep printing 388 } 389 390 var p *obj.Prog 391 var op *obj.Prog 392 393 p = cursym.Func.Text 394 if p == nil || p.Link == nil { // handle external functions and ELF section symbols 395 return 396 } 397 398 if oprange[AAND&obj.AMask] == nil { 399 ctxt.Diag("arm ops not initialized, call arm.buildop first") 400 } 401 402 c := ctxt5{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: p.To.Offset + 4} 403 pc := int32(0) 404 405 op = p 406 p = p.Link 407 var m int 408 var o *Optab 409 for ; p != nil || c.blitrl != nil; op, p = p, p.Link { 410 if p == nil { 411 if c.checkpool(op, pc) { 412 p = op 413 continue 414 } 415 416 // can't happen: blitrl is not nil, but checkpool didn't flushpool 417 ctxt.Diag("internal inconsistency") 418 419 break 420 } 421 422 p.Pc = int64(pc) 423 o = c.oplook(p) 424 m = int(o.size) 425 426 if m%4 != 0 || p.Pc%4 != 0 { 427 ctxt.Diag("!pc invalid: %v size=%d", p, m) 428 } 429 430 // must check literal pool here in case p generates many instructions 431 if c.blitrl != nil { 432 // Emit the constant pool just before p if p 433 // would push us over the immediate size limit. 434 if c.checkpool(op, pc+int32(m)) { 435 // Back up to the instruction just 436 // before the pool and continue with 437 // the first instruction of the pool. 438 p = op 439 continue 440 } 441 } 442 443 if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) { 444 ctxt.Diag("zero-width instruction\n%v", p) 445 continue 446 } 447 448 switch o.flag & (LFROM | LTO | LPOOL) { 449 case LFROM: 450 c.addpool(p, &p.From) 451 452 case LTO: 453 c.addpool(p, &p.To) 454 455 case LPOOL: 456 if p.Scond&C_SCOND == C_SCOND_NONE { 457 c.flushpool(p, 0, 0) 458 } 459 } 460 461 if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE { 462 c.flushpool(p, 0, 0) 463 } 464 465 pc += int32(m) 466 } 467 468 c.cursym.Size = int64(pc) 469 470 /* 471 * if any procedure is large enough to 472 * generate a large SBRA branch, then 473 * generate extra passes putting branches 474 * around jmps to fix. this is rare. 475 */ 476 times := 0 477 478 var bflag int 479 var opc int32 480 var out [6 + 3]uint32 481 for { 482 bflag = 0 483 pc = 0 484 times++ 485 c.cursym.Func.Text.Pc = 0 // force re-layout the code. 486 for p = c.cursym.Func.Text; p != nil; p = p.Link { 487 o = c.oplook(p) 488 if int64(pc) > p.Pc { 489 p.Pc = int64(pc) 490 } 491 492 /* very large branches 493 if(o->type == 6 && p->pcond) { 494 otxt = p->pcond->pc - c; 495 if(otxt < 0) 496 otxt = -otxt; 497 if(otxt >= (1L<<17) - 10) { 498 q = emallocz(sizeof(Prog)); 499 q->link = p->link; 500 p->link = q; 501 q->as = AB; 502 q->to.type = TYPE_BRANCH; 503 q->pcond = p->pcond; 504 p->pcond = q; 505 q = emallocz(sizeof(Prog)); 506 q->link = p->link; 507 p->link = q; 508 q->as = AB; 509 q->to.type = TYPE_BRANCH; 510 q->pcond = q->link->link; 511 bflag = 1; 512 } 513 } 514 */ 515 opc = int32(p.Pc) 516 m = int(o.size) 517 if p.Pc != int64(opc) { 518 bflag = 1 519 } 520 521 //print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times); 522 pc = int32(p.Pc + int64(m)) 523 524 if m%4 != 0 || p.Pc%4 != 0 { 525 ctxt.Diag("pc invalid: %v size=%d", p, m) 526 } 527 528 if m/4 > len(out) { 529 ctxt.Diag("instruction size too large: %d > %d", m/4, len(out)) 530 } 531 if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.ANOP) { 532 if p.As == obj.ATEXT { 533 c.autosize = p.To.Offset + 4 534 continue 535 } 536 537 ctxt.Diag("zero-width instruction\n%v", p) 538 continue 539 } 540 } 541 542 c.cursym.Size = int64(pc) 543 if bflag == 0 { 544 break 545 } 546 } 547 548 if pc%4 != 0 { 549 ctxt.Diag("sym->size=%d, invalid", pc) 550 } 551 552 /* 553 * lay out the code. all the pc-relative code references, 554 * even cross-function, are resolved now; 555 * only data references need to be relocated. 556 * with more work we could leave cross-function 557 * code references to be relocated too, and then 558 * perhaps we'd be able to parallelize the span loop above. 559 */ 560 561 p = c.cursym.Func.Text 562 c.autosize = p.To.Offset + 4 563 c.cursym.Grow(c.cursym.Size) 564 565 bp := c.cursym.P 566 pc = int32(p.Pc) // even p->link might need extra padding 567 var v int 568 for p = p.Link; p != nil; p = p.Link { 569 c.pc = p.Pc 570 o = c.oplook(p) 571 opc = int32(p.Pc) 572 c.asmout(p, o, out[:]) 573 m = int(o.size) 574 575 if m%4 != 0 || p.Pc%4 != 0 { 576 ctxt.Diag("final stage: pc invalid: %v size=%d", p, m) 577 } 578 579 if int64(pc) > p.Pc { 580 ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, pc, p) 581 } 582 for int64(pc) != p.Pc { 583 // emit 0xe1a00000 (MOVW R0, R0) 584 bp[0] = 0x00 585 bp = bp[1:] 586 587 bp[0] = 0x00 588 bp = bp[1:] 589 bp[0] = 0xa0 590 bp = bp[1:] 591 bp[0] = 0xe1 592 bp = bp[1:] 593 pc += 4 594 } 595 596 for i := 0; i < m/4; i++ { 597 v = int(out[i]) 598 bp[0] = byte(v) 599 bp = bp[1:] 600 bp[0] = byte(v >> 8) 601 bp = bp[1:] 602 bp[0] = byte(v >> 16) 603 bp = bp[1:] 604 bp[0] = byte(v >> 24) 605 bp = bp[1:] 606 } 607 608 pc += int32(m) 609 } 610 } 611 612 // checkpool flushes the literal pool when the first reference to 613 // it threatens to go out of range of a 12-bit PC-relative offset. 614 // 615 // nextpc is the tentative next PC at which the pool could be emitted. 616 // checkpool should be called *before* emitting the instruction that 617 // would cause the PC to reach nextpc. 618 // If nextpc is too far from the first pool reference, checkpool will 619 // flush the pool immediately after p. 620 // The caller should resume processing a p.Link. 621 func (c *ctxt5) checkpool(p *obj.Prog, nextpc int32) bool { 622 poolLast := nextpc 623 poolLast += 4 // the AB instruction to jump around the pool 624 poolLast += int32(c.pool.size) - 4 // the offset of the last pool entry 625 626 refPC := int32(c.pool.start) // PC of the first pool reference 627 628 v := poolLast - refPC - 8 // 12-bit PC-relative offset (see omvl) 629 630 if c.pool.size >= 0xff0 || immaddr(v) == 0 { 631 return c.flushpool(p, 1, 0) 632 } else if p.Link == nil { 633 return c.flushpool(p, 2, 0) 634 } 635 return false 636 } 637 638 func (c *ctxt5) flushpool(p *obj.Prog, skip int, force int) bool { 639 if c.blitrl != nil { 640 if skip != 0 { 641 if false && skip == 1 { 642 fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), c.pool.size, c.pool.start) 643 } 644 q := c.newprog() 645 q.As = AB 646 q.To.Type = obj.TYPE_BRANCH 647 q.To.SetTarget(p.Link) 648 q.Link = c.blitrl 649 q.Pos = p.Pos 650 c.blitrl = q 651 } else if force == 0 && (p.Pc+int64(c.pool.size)-int64(c.pool.start) < 2048) { 652 return false 653 } 654 655 // The line number for constant pool entries doesn't really matter. 656 // We set it to the line number of the preceding instruction so that 657 // there are no deltas to encode in the pc-line tables. 658 for q := c.blitrl; q != nil; q = q.Link { 659 q.Pos = p.Pos 660 } 661 662 c.elitrl.Link = p.Link 663 p.Link = c.blitrl 664 665 c.blitrl = nil /* BUG: should refer back to values until out-of-range */ 666 c.elitrl = nil 667 c.pool.size = 0 668 c.pool.start = 0 669 c.pool.extra = 0 670 return true 671 } 672 673 return false 674 } 675 676 func (c *ctxt5) addpool(p *obj.Prog, a *obj.Addr) { 677 t := c.newprog() 678 t.As = AWORD 679 680 switch c.aclass(a) { 681 default: 682 t.To.Offset = a.Offset 683 t.To.Sym = a.Sym 684 t.To.Type = a.Type 685 t.To.Name = a.Name 686 687 if c.ctxt.Flag_shared && t.To.Sym != nil { 688 t.Rel = p 689 } 690 691 case C_SROREG, 692 C_LOREG, 693 C_ROREG, 694 C_FOREG, 695 C_SOREG, 696 C_HOREG, 697 C_FAUTO, 698 C_SAUTO, 699 C_LAUTO, 700 C_LACON: 701 t.To.Type = obj.TYPE_CONST 702 t.To.Offset = c.instoffset 703 } 704 705 if t.Rel == nil { 706 for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */ 707 if q.Rel == nil && q.To == t.To { 708 p.Pool = q 709 return 710 } 711 } 712 } 713 714 q := c.newprog() 715 *q = *t 716 q.Pc = int64(c.pool.size) 717 718 if c.blitrl == nil { 719 c.blitrl = q 720 c.pool.start = uint32(p.Pc) 721 } else { 722 c.elitrl.Link = q 723 } 724 c.elitrl = q 725 c.pool.size += 4 726 727 // Store the link to the pool entry in Pool. 728 p.Pool = q 729 } 730 731 func (c *ctxt5) regoff(a *obj.Addr) int32 { 732 c.instoffset = 0 733 c.aclass(a) 734 return int32(c.instoffset) 735 } 736 737 func immrot(v uint32) int32 { 738 for i := 0; i < 16; i++ { 739 if v&^0xff == 0 { 740 return int32(uint32(int32(i)<<8) | v | 1<<25) 741 } 742 v = v<<2 | v>>30 743 } 744 745 return 0 746 } 747 748 // immrot2a returns bits encoding the immediate constant fields of two instructions, 749 // such that the encoded constants x, y satisfy x|y==v, x&y==0. 750 // Returns 0,0 if no such decomposition of v exists. 751 func immrot2a(v uint32) (uint32, uint32) { 752 for i := uint(1); i < 32; i++ { 753 m := uint32(1<<i - 1) 754 if x, y := immrot(v&m), immrot(v&^m); x != 0 && y != 0 { 755 return uint32(x), uint32(y) 756 } 757 } 758 // TODO: handle some more cases, like where 759 // the wraparound from the rotate could help. 760 return 0, 0 761 } 762 763 // immrot2s returns bits encoding the immediate constant fields of two instructions, 764 // such that the encoded constants y, x satisfy y-x==v, y&x==0. 765 // Returns 0,0 if no such decomposition of v exists. 766 func immrot2s(v uint32) (uint32, uint32) { 767 if immrot(v) != 0 { 768 return v, 0 769 } 770 // suppose v in the form of {leading 00, upper effective bits, lower 8 effective bits, trailing 00} 771 // omit trailing 00 772 var i uint32 773 for i = 2; i < 32; i += 2 { 774 if v&(1<<i-1) != 0 { 775 break 776 } 777 } 778 // i must be <= 24, then adjust i just above lower 8 effective bits of v 779 i += 6 780 // let x = {the complement of lower 8 effective bits, trailing 00}, y = x + v 781 x := 1<<i - v&(1<<i-1) 782 y := v + x 783 if y, x = uint32(immrot(y)), uint32(immrot(x)); y != 0 && x != 0 { 784 return y, x 785 } 786 return 0, 0 787 } 788 789 func immaddr(v int32) int32 { 790 if v >= 0 && v <= 0xfff { 791 return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */ 792 } 793 if v >= -0xfff && v < 0 { 794 return -v&0xfff | 1<<24 /* pre indexing */ 795 } 796 return 0 797 } 798 799 func immfloat(v int32) bool { 800 return v&0xC03 == 0 /* offset will fit in floating-point load/store */ 801 } 802 803 func immhalf(v int32) bool { 804 if v >= 0 && v <= 0xff { 805 return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */ 806 } 807 if v >= -0xff && v < 0 { 808 return -v&0xff|1<<24 != 0 /* pre indexing */ 809 } 810 return false 811 } 812 813 func (c *ctxt5) aclass(a *obj.Addr) int { 814 switch a.Type { 815 case obj.TYPE_NONE: 816 return C_NONE 817 818 case obj.TYPE_REG: 819 c.instoffset = 0 820 if REG_R0 <= a.Reg && a.Reg <= REG_R15 { 821 return C_REG 822 } 823 if REG_F0 <= a.Reg && a.Reg <= REG_F15 { 824 return C_FREG 825 } 826 if a.Reg == REG_FPSR || a.Reg == REG_FPCR { 827 return C_FCR 828 } 829 if a.Reg == REG_CPSR || a.Reg == REG_SPSR { 830 return C_PSR 831 } 832 if a.Reg >= REG_SPECIAL { 833 return C_SPR 834 } 835 return C_GOK 836 837 case obj.TYPE_REGREG: 838 return C_REGREG 839 840 case obj.TYPE_REGREG2: 841 return C_REGREG2 842 843 case obj.TYPE_REGLIST: 844 return C_REGLIST 845 846 case obj.TYPE_SHIFT: 847 if a.Reg == 0 { 848 // register shift R>>i 849 return C_SHIFT 850 } else { 851 // memory address with shifted offset R>>i(R) 852 return C_SHIFTADDR 853 } 854 855 case obj.TYPE_MEM: 856 switch a.Name { 857 case obj.NAME_EXTERN, 858 obj.NAME_GOTREF, 859 obj.NAME_STATIC: 860 if a.Sym == nil || a.Sym.Name == "" { 861 fmt.Printf("null sym external\n") 862 return C_GOK 863 } 864 865 c.instoffset = 0 // s.b. unused but just in case 866 if a.Sym.Type == objabi.STLSBSS { 867 if c.ctxt.Flag_shared { 868 return C_TLS_IE 869 } else { 870 return C_TLS_LE 871 } 872 } 873 874 return C_ADDR 875 876 case obj.NAME_AUTO: 877 if a.Reg == REGSP { 878 // unset base register for better printing, since 879 // a.Offset is still relative to pseudo-SP. 880 a.Reg = obj.REG_NONE 881 } 882 c.instoffset = c.autosize + a.Offset 883 if t := immaddr(int32(c.instoffset)); t != 0 { 884 if immhalf(int32(c.instoffset)) { 885 if immfloat(t) { 886 return C_HFAUTO 887 } 888 return C_HAUTO 889 } 890 891 if immfloat(t) { 892 return C_FAUTO 893 } 894 return C_SAUTO 895 } 896 897 return C_LAUTO 898 899 case obj.NAME_PARAM: 900 if a.Reg == REGSP { 901 // unset base register for better printing, since 902 // a.Offset is still relative to pseudo-FP. 903 a.Reg = obj.REG_NONE 904 } 905 c.instoffset = c.autosize + a.Offset + 4 906 if t := immaddr(int32(c.instoffset)); t != 0 { 907 if immhalf(int32(c.instoffset)) { 908 if immfloat(t) { 909 return C_HFAUTO 910 } 911 return C_HAUTO 912 } 913 914 if immfloat(t) { 915 return C_FAUTO 916 } 917 return C_SAUTO 918 } 919 920 return C_LAUTO 921 922 case obj.NAME_NONE: 923 c.instoffset = a.Offset 924 if t := immaddr(int32(c.instoffset)); t != 0 { 925 if immhalf(int32(c.instoffset)) { /* n.b. that it will also satisfy immrot */ 926 if immfloat(t) { 927 return C_HFOREG 928 } 929 return C_HOREG 930 } 931 932 if immfloat(t) { 933 return C_FOREG /* n.b. that it will also satisfy immrot */ 934 } 935 if immrot(uint32(c.instoffset)) != 0 { 936 return C_SROREG 937 } 938 if immhalf(int32(c.instoffset)) { 939 return C_HOREG 940 } 941 return C_SOREG 942 } 943 944 if immrot(uint32(c.instoffset)) != 0 { 945 return C_ROREG 946 } 947 return C_LOREG 948 } 949 950 return C_GOK 951 952 case obj.TYPE_FCONST: 953 if c.chipzero5(a.Val.(float64)) >= 0 { 954 return C_ZFCON 955 } 956 if c.chipfloat5(a.Val.(float64)) >= 0 { 957 return C_SFCON 958 } 959 return C_LFCON 960 961 case obj.TYPE_TEXTSIZE: 962 return C_TEXTSIZE 963 964 case obj.TYPE_CONST, 965 obj.TYPE_ADDR: 966 switch a.Name { 967 case obj.NAME_NONE: 968 c.instoffset = a.Offset 969 if a.Reg != 0 { 970 return c.aconsize() 971 } 972 973 if immrot(uint32(c.instoffset)) != 0 { 974 return C_RCON 975 } 976 if immrot(^uint32(c.instoffset)) != 0 { 977 return C_NCON 978 } 979 if uint32(c.instoffset) <= 0xffff && objabi.GOARM == 7 { 980 return C_SCON 981 } 982 if x, y := immrot2a(uint32(c.instoffset)); x != 0 && y != 0 { 983 return C_RCON2A 984 } 985 if y, x := immrot2s(uint32(c.instoffset)); x != 0 && y != 0 { 986 return C_RCON2S 987 } 988 return C_LCON 989 990 case obj.NAME_EXTERN, 991 obj.NAME_GOTREF, 992 obj.NAME_STATIC: 993 s := a.Sym 994 if s == nil { 995 break 996 } 997 c.instoffset = 0 // s.b. unused but just in case 998 return C_LCONADDR 999 1000 case obj.NAME_AUTO: 1001 if a.Reg == REGSP { 1002 // unset base register for better printing, since 1003 // a.Offset is still relative to pseudo-SP. 1004 a.Reg = obj.REG_NONE 1005 } 1006 c.instoffset = c.autosize + a.Offset 1007 return c.aconsize() 1008 1009 case obj.NAME_PARAM: 1010 if a.Reg == REGSP { 1011 // unset base register for better printing, since 1012 // a.Offset is still relative to pseudo-FP. 1013 a.Reg = obj.REG_NONE 1014 } 1015 c.instoffset = c.autosize + a.Offset + 4 1016 return c.aconsize() 1017 } 1018 1019 return C_GOK 1020 1021 case obj.TYPE_BRANCH: 1022 return C_SBRA 1023 } 1024 1025 return C_GOK 1026 } 1027 1028 func (c *ctxt5) aconsize() int { 1029 if immrot(uint32(c.instoffset)) != 0 { 1030 return C_RACON 1031 } 1032 if immrot(uint32(-c.instoffset)) != 0 { 1033 return C_RACON 1034 } 1035 return C_LACON 1036 } 1037 1038 func (c *ctxt5) oplook(p *obj.Prog) *Optab { 1039 a1 := int(p.Optab) 1040 if a1 != 0 { 1041 return &optab[a1-1] 1042 } 1043 a1 = int(p.From.Class) 1044 if a1 == 0 { 1045 a1 = c.aclass(&p.From) + 1 1046 p.From.Class = int8(a1) 1047 } 1048 1049 a1-- 1050 a3 := int(p.To.Class) 1051 if a3 == 0 { 1052 a3 = c.aclass(&p.To) + 1 1053 p.To.Class = int8(a3) 1054 } 1055 1056 a3-- 1057 a2 := C_NONE 1058 if p.Reg != 0 { 1059 switch { 1060 case REG_F0 <= p.Reg && p.Reg <= REG_F15: 1061 a2 = C_FREG 1062 case REG_R0 <= p.Reg && p.Reg <= REG_R15: 1063 a2 = C_REG 1064 default: 1065 c.ctxt.Diag("invalid register in %v", p) 1066 } 1067 } 1068 1069 // check illegal base register 1070 switch a1 { 1071 case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR: 1072 if p.From.Reg < REG_R0 || REG_R15 < p.From.Reg { 1073 c.ctxt.Diag("illegal base register: %v", p) 1074 } 1075 default: 1076 } 1077 switch a3 { 1078 case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFTADDR: 1079 if p.To.Reg < REG_R0 || REG_R15 < p.To.Reg { 1080 c.ctxt.Diag("illegal base register: %v", p) 1081 } 1082 default: 1083 } 1084 1085 // If current instruction has a .S suffix (flags update), 1086 // we must use the constant pool instead of splitting it. 1087 if (a1 == C_RCON2A || a1 == C_RCON2S) && p.Scond&C_SBIT != 0 { 1088 a1 = C_LCON 1089 } 1090 if (a3 == C_RCON2A || a3 == C_RCON2S) && p.Scond&C_SBIT != 0 { 1091 a3 = C_LCON 1092 } 1093 1094 if false { /*debug['O']*/ 1095 fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3)) 1096 fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type) 1097 } 1098 1099 ops := oprange[p.As&obj.AMask] 1100 c1 := &xcmp[a1] 1101 c3 := &xcmp[a3] 1102 for i := range ops { 1103 op := &ops[i] 1104 if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] { 1105 p.Optab = uint16(cap(optab) - cap(ops) + i + 1) 1106 checkSuffix(c, p, op) 1107 return op 1108 } 1109 } 1110 1111 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) 1112 if ops == nil { 1113 ops = optab 1114 } 1115 return &ops[0] 1116 } 1117 1118 func cmp(a int, b int) bool { 1119 if a == b { 1120 return true 1121 } 1122 switch a { 1123 case C_LCON: 1124 if b == C_RCON || b == C_NCON || b == C_SCON || b == C_RCON2A || b == C_RCON2S { 1125 return true 1126 } 1127 1128 case C_LACON: 1129 if b == C_RACON { 1130 return true 1131 } 1132 1133 case C_LFCON: 1134 if b == C_ZFCON || b == C_SFCON { 1135 return true 1136 } 1137 1138 case C_HFAUTO: 1139 return b == C_HAUTO || b == C_FAUTO 1140 1141 case C_FAUTO, C_HAUTO: 1142 return b == C_HFAUTO 1143 1144 case C_SAUTO: 1145 return cmp(C_HFAUTO, b) 1146 1147 case C_LAUTO: 1148 return cmp(C_SAUTO, b) 1149 1150 case C_HFOREG: 1151 return b == C_HOREG || b == C_FOREG 1152 1153 case C_FOREG, C_HOREG: 1154 return b == C_HFOREG 1155 1156 case C_SROREG: 1157 return cmp(C_SOREG, b) || cmp(C_ROREG, b) 1158 1159 case C_SOREG, C_ROREG: 1160 return b == C_SROREG || cmp(C_HFOREG, b) 1161 1162 case C_LOREG: 1163 return cmp(C_SROREG, b) 1164 1165 case C_LBRA: 1166 if b == C_SBRA { 1167 return true 1168 } 1169 1170 case C_HREG: 1171 return cmp(C_SP, b) || cmp(C_PC, b) 1172 } 1173 1174 return false 1175 } 1176 1177 type ocmp []Optab 1178 1179 func (x ocmp) Len() int { 1180 return len(x) 1181 } 1182 1183 func (x ocmp) Swap(i, j int) { 1184 x[i], x[j] = x[j], x[i] 1185 } 1186 1187 func (x ocmp) Less(i, j int) bool { 1188 p1 := &x[i] 1189 p2 := &x[j] 1190 n := int(p1.as) - int(p2.as) 1191 if n != 0 { 1192 return n < 0 1193 } 1194 n = int(p1.a1) - int(p2.a1) 1195 if n != 0 { 1196 return n < 0 1197 } 1198 n = int(p1.a2) - int(p2.a2) 1199 if n != 0 { 1200 return n < 0 1201 } 1202 n = int(p1.a3) - int(p2.a3) 1203 if n != 0 { 1204 return n < 0 1205 } 1206 return false 1207 } 1208 1209 func opset(a, b0 obj.As) { 1210 oprange[a&obj.AMask] = oprange[b0] 1211 } 1212 1213 func buildop(ctxt *obj.Link) { 1214 if oprange[AAND&obj.AMask] != nil { 1215 // Already initialized; stop now. 1216 // This happens in the cmd/asm tests, 1217 // each of which re-initializes the arch. 1218 return 1219 } 1220 1221 deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal) 1222 1223 symdiv = ctxt.Lookup("runtime._div") 1224 symdivu = ctxt.Lookup("runtime._divu") 1225 symmod = ctxt.Lookup("runtime._mod") 1226 symmodu = ctxt.Lookup("runtime._modu") 1227 1228 var n int 1229 1230 for i := 0; i < C_GOK; i++ { 1231 for n = 0; n < C_GOK; n++ { 1232 if cmp(n, i) { 1233 xcmp[i][n] = true 1234 } 1235 } 1236 } 1237 for n = 0; optab[n].as != obj.AXXX; n++ { 1238 if optab[n].flag&LPCREL != 0 { 1239 if ctxt.Flag_shared { 1240 optab[n].size += int8(optab[n].pcrelsiz) 1241 } else { 1242 optab[n].flag &^= LPCREL 1243 } 1244 } 1245 } 1246 1247 sort.Sort(ocmp(optab[:n])) 1248 for i := 0; i < n; i++ { 1249 r := optab[i].as 1250 r0 := r & obj.AMask 1251 start := i 1252 for optab[i].as == r { 1253 i++ 1254 } 1255 oprange[r0] = optab[start:i] 1256 i-- 1257 1258 switch r { 1259 default: 1260 ctxt.Diag("unknown op in build: %v", r) 1261 ctxt.DiagFlush() 1262 log.Fatalf("bad code") 1263 1264 case AADD: 1265 opset(ASUB, r0) 1266 opset(ARSB, r0) 1267 opset(AADC, r0) 1268 opset(ASBC, r0) 1269 opset(ARSC, r0) 1270 1271 case AORR: 1272 opset(AEOR, r0) 1273 opset(ABIC, r0) 1274 1275 case ACMP: 1276 opset(ATEQ, r0) 1277 opset(ACMN, r0) 1278 opset(ATST, r0) 1279 1280 case AMVN: 1281 break 1282 1283 case ABEQ: 1284 opset(ABNE, r0) 1285 opset(ABCS, r0) 1286 opset(ABHS, r0) 1287 opset(ABCC, r0) 1288 opset(ABLO, r0) 1289 opset(ABMI, r0) 1290 opset(ABPL, r0) 1291 opset(ABVS, r0) 1292 opset(ABVC, r0) 1293 opset(ABHI, r0) 1294 opset(ABLS, r0) 1295 opset(ABGE, r0) 1296 opset(ABLT, r0) 1297 opset(ABGT, r0) 1298 opset(ABLE, r0) 1299 1300 case ASLL: 1301 opset(ASRL, r0) 1302 opset(ASRA, r0) 1303 1304 case AMUL: 1305 opset(AMULU, r0) 1306 1307 case ADIV: 1308 opset(AMOD, r0) 1309 opset(AMODU, r0) 1310 opset(ADIVU, r0) 1311 1312 case ADIVHW: 1313 opset(ADIVUHW, r0) 1314 1315 case AMOVW, 1316 AMOVB, 1317 AMOVBS, 1318 AMOVBU, 1319 AMOVH, 1320 AMOVHS, 1321 AMOVHU: 1322 break 1323 1324 case ASWPW: 1325 opset(ASWPBU, r0) 1326 1327 case AB, 1328 ABL, 1329 ABX, 1330 ABXRET, 1331 obj.ADUFFZERO, 1332 obj.ADUFFCOPY, 1333 ASWI, 1334 AWORD, 1335 AMOVM, 1336 ARFE, 1337 obj.ATEXT: 1338 break 1339 1340 case AADDF: 1341 opset(AADDD, r0) 1342 opset(ASUBF, r0) 1343 opset(ASUBD, r0) 1344 opset(AMULF, r0) 1345 opset(AMULD, r0) 1346 opset(ANMULF, r0) 1347 opset(ANMULD, r0) 1348 opset(AMULAF, r0) 1349 opset(AMULAD, r0) 1350 opset(AMULSF, r0) 1351 opset(AMULSD, r0) 1352 opset(ANMULAF, r0) 1353 opset(ANMULAD, r0) 1354 opset(ANMULSF, r0) 1355 opset(ANMULSD, r0) 1356 opset(AFMULAF, r0) 1357 opset(AFMULAD, r0) 1358 opset(AFMULSF, r0) 1359 opset(AFMULSD, r0) 1360 opset(AFNMULAF, r0) 1361 opset(AFNMULAD, r0) 1362 opset(AFNMULSF, r0) 1363 opset(AFNMULSD, r0) 1364 opset(ADIVF, r0) 1365 opset(ADIVD, r0) 1366 1367 case ANEGF: 1368 opset(ANEGD, r0) 1369 opset(ASQRTF, r0) 1370 opset(ASQRTD, r0) 1371 opset(AMOVFD, r0) 1372 opset(AMOVDF, r0) 1373 opset(AABSF, r0) 1374 opset(AABSD, r0) 1375 1376 case ACMPF: 1377 opset(ACMPD, r0) 1378 1379 case AMOVF: 1380 opset(AMOVD, r0) 1381 1382 case AMOVFW: 1383 opset(AMOVDW, r0) 1384 1385 case AMOVWF: 1386 opset(AMOVWD, r0) 1387 1388 case AMULL: 1389 opset(AMULAL, r0) 1390 opset(AMULLU, r0) 1391 opset(AMULALU, r0) 1392 1393 case AMULWT: 1394 opset(AMULWB, r0) 1395 opset(AMULBB, r0) 1396 opset(AMMUL, r0) 1397 1398 case AMULAWT: 1399 opset(AMULAWB, r0) 1400 opset(AMULABB, r0) 1401 opset(AMULS, r0) 1402 opset(AMMULA, r0) 1403 opset(AMMULS, r0) 1404 1405 case ABFX: 1406 opset(ABFXU, r0) 1407 opset(ABFC, r0) 1408 opset(ABFI, r0) 1409 1410 case ACLZ: 1411 opset(AREV, r0) 1412 opset(AREV16, r0) 1413 opset(AREVSH, r0) 1414 opset(ARBIT, r0) 1415 1416 case AXTAB: 1417 opset(AXTAH, r0) 1418 opset(AXTABU, r0) 1419 opset(AXTAHU, r0) 1420 1421 case ALDREX, 1422 ASTREX, 1423 ALDREXD, 1424 ASTREXD, 1425 ADMB, 1426 APLD, 1427 AAND, 1428 AMULA, 1429 obj.AUNDEF, 1430 obj.AFUNCDATA, 1431 obj.APCDATA, 1432 obj.ANOP: 1433 break 1434 } 1435 } 1436 } 1437 1438 func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) { 1439 c.printp = p 1440 o1 := uint32(0) 1441 o2 := uint32(0) 1442 o3 := uint32(0) 1443 o4 := uint32(0) 1444 o5 := uint32(0) 1445 o6 := uint32(0) 1446 if false { /*debug['P']*/ 1447 fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_) 1448 } 1449 switch o.type_ { 1450 default: 1451 c.ctxt.Diag("%v: unknown asm %d", p, o.type_) 1452 1453 case 0: /* pseudo ops */ 1454 if false { /*debug['G']*/ 1455 fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name) 1456 } 1457 1458 case 1: /* op R,[R],R */ 1459 o1 = c.oprrr(p, p.As, int(p.Scond)) 1460 1461 rf := int(p.From.Reg) 1462 rt := int(p.To.Reg) 1463 r := int(p.Reg) 1464 if p.To.Type == obj.TYPE_NONE { 1465 rt = 0 1466 } 1467 if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN { 1468 r = 0 1469 } else if r == 0 { 1470 r = rt 1471 } 1472 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1473 1474 case 2: /* movbu $I,[R],R */ 1475 c.aclass(&p.From) 1476 1477 o1 = c.oprrr(p, p.As, int(p.Scond)) 1478 o1 |= uint32(immrot(uint32(c.instoffset))) 1479 rt := int(p.To.Reg) 1480 r := int(p.Reg) 1481 if p.To.Type == obj.TYPE_NONE { 1482 rt = 0 1483 } 1484 if p.As == AMOVW || p.As == AMVN { 1485 r = 0 1486 } else if r == 0 { 1487 r = rt 1488 } 1489 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1490 1491 case 106: /* op $I,R,R where I can be decomposed into 2 immediates */ 1492 c.aclass(&p.From) 1493 r := int(p.Reg) 1494 rt := int(p.To.Reg) 1495 if r == 0 { 1496 r = rt 1497 } 1498 x, y := immrot2a(uint32(c.instoffset)) 1499 var as2 obj.As 1500 switch p.As { 1501 case AADD, ASUB, AORR, AEOR, ABIC: 1502 as2 = p.As // ADD, SUB, ORR, EOR, BIC 1503 case ARSB: 1504 as2 = AADD // RSB -> RSB/ADD pair 1505 case AADC: 1506 as2 = AADD // ADC -> ADC/ADD pair 1507 case ASBC: 1508 as2 = ASUB // SBC -> SBC/SUB pair 1509 case ARSC: 1510 as2 = AADD // RSC -> RSC/ADD pair 1511 default: 1512 c.ctxt.Diag("unknown second op for %v", p) 1513 } 1514 o1 = c.oprrr(p, p.As, int(p.Scond)) 1515 o2 = c.oprrr(p, as2, int(p.Scond)) 1516 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1517 o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12 1518 o1 |= x 1519 o2 |= y 1520 1521 case 107: /* op $I,R,R where I can be decomposed into 2 immediates */ 1522 c.aclass(&p.From) 1523 r := int(p.Reg) 1524 rt := int(p.To.Reg) 1525 if r == 0 { 1526 r = rt 1527 } 1528 y, x := immrot2s(uint32(c.instoffset)) 1529 var as2 obj.As 1530 switch p.As { 1531 case AADD: 1532 as2 = ASUB // ADD -> ADD/SUB pair 1533 case ASUB: 1534 as2 = AADD // SUB -> SUB/ADD pair 1535 case ARSB: 1536 as2 = ASUB // RSB -> RSB/SUB pair 1537 case AADC: 1538 as2 = ASUB // ADC -> ADC/SUB pair 1539 case ASBC: 1540 as2 = AADD // SBC -> SBC/ADD pair 1541 case ARSC: 1542 as2 = ASUB // RSC -> RSC/SUB pair 1543 default: 1544 c.ctxt.Diag("unknown second op for %v", p) 1545 } 1546 o1 = c.oprrr(p, p.As, int(p.Scond)) 1547 o2 = c.oprrr(p, as2, int(p.Scond)) 1548 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1549 o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12 1550 o1 |= y 1551 o2 |= x 1552 1553 case 3: /* add R<<[IR],[R],R */ 1554 o1 = c.mov(p) 1555 1556 case 4: /* MOVW $off(R), R -> add $off,[R],R */ 1557 c.aclass(&p.From) 1558 if c.instoffset < 0 { 1559 o1 = c.oprrr(p, ASUB, int(p.Scond)) 1560 o1 |= uint32(immrot(uint32(-c.instoffset))) 1561 } else { 1562 o1 = c.oprrr(p, AADD, int(p.Scond)) 1563 o1 |= uint32(immrot(uint32(c.instoffset))) 1564 } 1565 r := int(p.From.Reg) 1566 if r == 0 { 1567 r = int(o.param) 1568 } 1569 o1 |= (uint32(r) & 15) << 16 1570 o1 |= (uint32(p.To.Reg) & 15) << 12 1571 1572 case 5: /* bra s */ 1573 o1 = c.opbra(p, p.As, int(p.Scond)) 1574 1575 v := int32(-8) 1576 if p.To.Sym != nil { 1577 rel := obj.Addrel(c.cursym) 1578 rel.Off = int32(c.pc) 1579 rel.Siz = 4 1580 rel.Sym = p.To.Sym 1581 v += int32(p.To.Offset) 1582 rel.Add = int64(o1) | (int64(v)>>2)&0xffffff 1583 rel.Type = objabi.R_CALLARM 1584 break 1585 } 1586 1587 if p.To.Target() != nil { 1588 v = int32((p.To.Target().Pc - c.pc) - 8) 1589 } 1590 o1 |= (uint32(v) >> 2) & 0xffffff 1591 1592 case 6: /* b ,O(R) -> add $O,R,PC */ 1593 c.aclass(&p.To) 1594 1595 o1 = c.oprrr(p, AADD, int(p.Scond)) 1596 o1 |= uint32(immrot(uint32(c.instoffset))) 1597 o1 |= (uint32(p.To.Reg) & 15) << 16 1598 o1 |= (REGPC & 15) << 12 1599 1600 case 7: /* bl (R) -> blx R */ 1601 c.aclass(&p.To) 1602 1603 if c.instoffset != 0 { 1604 c.ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, c.instoffset) 1605 } 1606 o1 = c.oprrr(p, ABL, int(p.Scond)) 1607 o1 |= (uint32(p.To.Reg) & 15) << 0 1608 rel := obj.Addrel(c.cursym) 1609 rel.Off = int32(c.pc) 1610 rel.Siz = 0 1611 rel.Type = objabi.R_CALLIND 1612 1613 case 8: /* sll $c,[R],R -> mov (R<<$c),R */ 1614 c.aclass(&p.From) 1615 1616 o1 = c.oprrr(p, p.As, int(p.Scond)) 1617 r := int(p.Reg) 1618 if r == 0 { 1619 r = int(p.To.Reg) 1620 } 1621 o1 |= (uint32(r) & 15) << 0 1622 o1 |= uint32((c.instoffset & 31) << 7) 1623 o1 |= (uint32(p.To.Reg) & 15) << 12 1624 1625 case 9: /* sll R,[R],R -> mov (R<<R),R */ 1626 o1 = c.oprrr(p, p.As, int(p.Scond)) 1627 1628 r := int(p.Reg) 1629 if r == 0 { 1630 r = int(p.To.Reg) 1631 } 1632 o1 |= (uint32(r) & 15) << 0 1633 o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4 1634 o1 |= (uint32(p.To.Reg) & 15) << 12 1635 1636 case 10: /* swi [$con] */ 1637 o1 = c.oprrr(p, p.As, int(p.Scond)) 1638 1639 if p.To.Type != obj.TYPE_NONE { 1640 c.aclass(&p.To) 1641 o1 |= uint32(c.instoffset & 0xffffff) 1642 } 1643 1644 case 11: /* word */ 1645 c.aclass(&p.To) 1646 1647 o1 = uint32(c.instoffset) 1648 if p.To.Sym != nil { 1649 // This case happens with words generated 1650 // in the PC stream as part of the literal pool (c.pool). 1651 rel := obj.Addrel(c.cursym) 1652 1653 rel.Off = int32(c.pc) 1654 rel.Siz = 4 1655 rel.Sym = p.To.Sym 1656 rel.Add = p.To.Offset 1657 1658 if c.ctxt.Flag_shared { 1659 if p.To.Name == obj.NAME_GOTREF { 1660 rel.Type = objabi.R_GOTPCREL 1661 } else { 1662 rel.Type = objabi.R_PCREL 1663 } 1664 rel.Add += c.pc - p.Rel.Pc - 8 1665 } else { 1666 rel.Type = objabi.R_ADDR 1667 } 1668 o1 = 0 1669 } 1670 1671 case 12: /* movw $lcon, reg */ 1672 if o.a1 == C_SCON { 1673 o1 = c.omvs(p, &p.From, int(p.To.Reg)) 1674 } else if p.As == AMVN { 1675 o1 = c.omvr(p, &p.From, int(p.To.Reg)) 1676 } else { 1677 o1 = c.omvl(p, &p.From, int(p.To.Reg)) 1678 } 1679 1680 if o.flag&LPCREL != 0 { 1681 o2 = c.oprrr(p, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12 1682 } 1683 1684 case 13: /* op $lcon, [R], R */ 1685 if o.a1 == C_SCON { 1686 o1 = c.omvs(p, &p.From, REGTMP) 1687 } else { 1688 o1 = c.omvl(p, &p.From, REGTMP) 1689 } 1690 1691 if o1 == 0 { 1692 break 1693 } 1694 o2 = c.oprrr(p, p.As, int(p.Scond)) 1695 o2 |= REGTMP & 15 1696 r := int(p.Reg) 1697 if p.As == AMVN { 1698 r = 0 1699 } else if r == 0 { 1700 r = int(p.To.Reg) 1701 } 1702 o2 |= (uint32(r) & 15) << 16 1703 if p.To.Type != obj.TYPE_NONE { 1704 o2 |= (uint32(p.To.Reg) & 15) << 12 1705 } 1706 1707 case 14: /* movb/movbu/movh/movhu R,R */ 1708 o1 = c.oprrr(p, ASLL, int(p.Scond)) 1709 1710 if p.As == AMOVBU || p.As == AMOVHU { 1711 o2 = c.oprrr(p, ASRL, int(p.Scond)) 1712 } else { 1713 o2 = c.oprrr(p, ASRA, int(p.Scond)) 1714 } 1715 1716 r := int(p.To.Reg) 1717 o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12 1718 o2 |= uint32(r)&15 | (uint32(r)&15)<<12 1719 if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU { 1720 o1 |= 24 << 7 1721 o2 |= 24 << 7 1722 } else { 1723 o1 |= 16 << 7 1724 o2 |= 16 << 7 1725 } 1726 1727 case 15: /* mul r,[r,]r */ 1728 o1 = c.oprrr(p, p.As, int(p.Scond)) 1729 1730 rf := int(p.From.Reg) 1731 rt := int(p.To.Reg) 1732 r := int(p.Reg) 1733 if r == 0 { 1734 r = rt 1735 } 1736 1737 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 1738 1739 case 16: /* div r,[r,]r */ 1740 o1 = 0xf << 28 1741 1742 o2 = 0 1743 1744 case 17: 1745 o1 = c.oprrr(p, p.As, int(p.Scond)) 1746 rf := int(p.From.Reg) 1747 rt := int(p.To.Reg) 1748 rt2 := int(p.To.Offset) 1749 r := int(p.Reg) 1750 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12 1751 1752 case 18: /* BFX/BFXU/BFC/BFI */ 1753 o1 = c.oprrr(p, p.As, int(p.Scond)) 1754 rt := int(p.To.Reg) 1755 r := int(p.Reg) 1756 if r == 0 { 1757 r = rt 1758 } else if p.As == ABFC { // only "BFC $width, $lsb, Reg" is accepted, p.Reg must be 0 1759 c.ctxt.Diag("illegal combination: %v", p) 1760 } 1761 if p.GetFrom3() == nil || p.GetFrom3().Type != obj.TYPE_CONST { 1762 c.ctxt.Diag("%v: missing or wrong LSB", p) 1763 break 1764 } 1765 lsb := p.GetFrom3().Offset 1766 width := p.From.Offset 1767 if lsb < 0 || lsb > 31 || width <= 0 || (lsb+width) > 32 { 1768 c.ctxt.Diag("%v: wrong width or LSB", p) 1769 } 1770 switch p.As { 1771 case ABFX, ABFXU: // (width-1) is encoded 1772 o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(width-1)<<16 1773 case ABFC, ABFI: // MSB is encoded 1774 o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(lsb+width-1)<<16 1775 default: 1776 c.ctxt.Diag("illegal combination: %v", p) 1777 } 1778 1779 case 20: /* mov/movb/movbu R,O(R) */ 1780 c.aclass(&p.To) 1781 1782 r := int(p.To.Reg) 1783 if r == 0 { 1784 r = int(o.param) 1785 } 1786 o1 = c.osr(p.As, int(p.From.Reg), int32(c.instoffset), r, int(p.Scond)) 1787 1788 case 21: /* mov/movbu O(R),R -> lr */ 1789 c.aclass(&p.From) 1790 1791 r := int(p.From.Reg) 1792 if r == 0 { 1793 r = int(o.param) 1794 } 1795 o1 = c.olr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond)) 1796 if p.As != AMOVW { 1797 o1 |= 1 << 22 1798 } 1799 1800 case 22: /* XTAB R@>i, [R], R */ 1801 o1 = c.oprrr(p, p.As, int(p.Scond)) 1802 switch p.From.Offset &^ 0xf { 1803 // only 0/8/16/24 bits rotation is accepted 1804 case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7: 1805 o1 |= uint32(p.From.Offset) & 0xc0f 1806 default: 1807 c.ctxt.Diag("illegal shift: %v", p) 1808 } 1809 rt := p.To.Reg 1810 r := p.Reg 1811 if r == 0 { 1812 r = rt 1813 } 1814 o1 |= (uint32(rt)&15)<<12 | (uint32(r)&15)<<16 1815 1816 case 23: /* MOVW/MOVB/MOVH R@>i, R */ 1817 switch p.As { 1818 case AMOVW: 1819 o1 = c.mov(p) 1820 case AMOVBU, AMOVBS, AMOVB, AMOVHU, AMOVHS, AMOVH: 1821 o1 = c.movxt(p) 1822 default: 1823 c.ctxt.Diag("illegal combination: %v", p) 1824 } 1825 1826 case 30: /* mov/movb/movbu R,L(R) */ 1827 o1 = c.omvl(p, &p.To, REGTMP) 1828 1829 if o1 == 0 { 1830 break 1831 } 1832 r := int(p.To.Reg) 1833 if r == 0 { 1834 r = int(o.param) 1835 } 1836 o2 = c.osrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond)) 1837 if p.As != AMOVW { 1838 o2 |= 1 << 22 1839 } 1840 1841 case 31: /* mov/movbu L(R),R -> lr[b] */ 1842 o1 = c.omvl(p, &p.From, REGTMP) 1843 1844 if o1 == 0 { 1845 break 1846 } 1847 r := int(p.From.Reg) 1848 if r == 0 { 1849 r = int(o.param) 1850 } 1851 o2 = c.olrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond)) 1852 if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { 1853 o2 |= 1 << 22 1854 } 1855 1856 case 34: /* mov $lacon,R */ 1857 o1 = c.omvl(p, &p.From, REGTMP) 1858 1859 if o1 == 0 { 1860 break 1861 } 1862 1863 o2 = c.oprrr(p, AADD, int(p.Scond)) 1864 o2 |= REGTMP & 15 1865 r := int(p.From.Reg) 1866 if r == 0 { 1867 r = int(o.param) 1868 } 1869 o2 |= (uint32(r) & 15) << 16 1870 if p.To.Type != obj.TYPE_NONE { 1871 o2 |= (uint32(p.To.Reg) & 15) << 12 1872 } 1873 1874 case 35: /* mov PSR,R */ 1875 o1 = 2<<23 | 0xf<<16 | 0<<0 1876 1877 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1878 o1 |= (uint32(p.From.Reg) & 1) << 22 1879 o1 |= (uint32(p.To.Reg) & 15) << 12 1880 1881 case 36: /* mov R,PSR */ 1882 o1 = 2<<23 | 0x2cf<<12 | 0<<4 1883 1884 if p.Scond&C_FBIT != 0 { 1885 o1 ^= 0x010 << 12 1886 } 1887 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1888 o1 |= (uint32(p.To.Reg) & 1) << 22 1889 o1 |= (uint32(p.From.Reg) & 15) << 0 1890 1891 case 37: /* mov $con,PSR */ 1892 c.aclass(&p.From) 1893 1894 o1 = 2<<23 | 0x2cf<<12 | 0<<4 1895 if p.Scond&C_FBIT != 0 { 1896 o1 ^= 0x010 << 12 1897 } 1898 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1899 o1 |= uint32(immrot(uint32(c.instoffset))) 1900 o1 |= (uint32(p.To.Reg) & 1) << 22 1901 o1 |= (uint32(p.From.Reg) & 15) << 0 1902 1903 case 38, 39: 1904 switch o.type_ { 1905 case 38: /* movm $con,oreg -> stm */ 1906 o1 = 0x4 << 25 1907 1908 o1 |= uint32(p.From.Offset & 0xffff) 1909 o1 |= (uint32(p.To.Reg) & 15) << 16 1910 c.aclass(&p.To) 1911 1912 case 39: /* movm oreg,$con -> ldm */ 1913 o1 = 0x4<<25 | 1<<20 1914 1915 o1 |= uint32(p.To.Offset & 0xffff) 1916 o1 |= (uint32(p.From.Reg) & 15) << 16 1917 c.aclass(&p.From) 1918 } 1919 1920 if c.instoffset != 0 { 1921 c.ctxt.Diag("offset must be zero in MOVM; %v", p) 1922 } 1923 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1924 if p.Scond&C_PBIT != 0 { 1925 o1 |= 1 << 24 1926 } 1927 if p.Scond&C_UBIT != 0 { 1928 o1 |= 1 << 23 1929 } 1930 if p.Scond&C_WBIT != 0 { 1931 o1 |= 1 << 21 1932 } 1933 1934 case 40: /* swp oreg,reg,reg */ 1935 c.aclass(&p.From) 1936 1937 if c.instoffset != 0 { 1938 c.ctxt.Diag("offset must be zero in SWP") 1939 } 1940 o1 = 0x2<<23 | 0x9<<4 1941 if p.As != ASWPW { 1942 o1 |= 1 << 22 1943 } 1944 o1 |= (uint32(p.From.Reg) & 15) << 16 1945 o1 |= (uint32(p.Reg) & 15) << 0 1946 o1 |= (uint32(p.To.Reg) & 15) << 12 1947 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1948 1949 case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ 1950 o1 = 0xe8fd8000 1951 1952 case 50: /* floating point store */ 1953 v := c.regoff(&p.To) 1954 1955 r := int(p.To.Reg) 1956 if r == 0 { 1957 r = int(o.param) 1958 } 1959 o1 = c.ofsr(p.As, int(p.From.Reg), v, r, int(p.Scond), p) 1960 1961 case 51: /* floating point load */ 1962 v := c.regoff(&p.From) 1963 1964 r := int(p.From.Reg) 1965 if r == 0 { 1966 r = int(o.param) 1967 } 1968 o1 = c.ofsr(p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20 1969 1970 case 52: /* floating point store, int32 offset UGLY */ 1971 o1 = c.omvl(p, &p.To, REGTMP) 1972 1973 if o1 == 0 { 1974 break 1975 } 1976 r := int(p.To.Reg) 1977 if r == 0 { 1978 r = int(o.param) 1979 } 1980 o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 1981 o3 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p) 1982 1983 case 53: /* floating point load, int32 offset UGLY */ 1984 o1 = c.omvl(p, &p.From, REGTMP) 1985 1986 if o1 == 0 { 1987 break 1988 } 1989 r := int(p.From.Reg) 1990 if r == 0 { 1991 r = int(o.param) 1992 } 1993 o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 1994 o3 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 1995 1996 case 54: /* floating point arith */ 1997 o1 = c.oprrr(p, p.As, int(p.Scond)) 1998 1999 rf := int(p.From.Reg) 2000 rt := int(p.To.Reg) 2001 r := int(p.Reg) 2002 if r == 0 { 2003 switch p.As { 2004 case AMULAD, AMULAF, AMULSF, AMULSD, ANMULAF, ANMULAD, ANMULSF, ANMULSD, 2005 AFMULAD, AFMULAF, AFMULSF, AFMULSD, AFNMULAF, AFNMULAD, AFNMULSF, AFNMULSD: 2006 c.ctxt.Diag("illegal combination: %v", p) 2007 default: 2008 r = rt 2009 } 2010 } 2011 2012 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 2013 2014 case 55: /* negf freg, freg */ 2015 o1 = c.oprrr(p, p.As, int(p.Scond)) 2016 2017 rf := int(p.From.Reg) 2018 rt := int(p.To.Reg) 2019 2020 o1 |= (uint32(rf)&15)<<0 | (uint32(rt)&15)<<12 2021 2022 case 56: /* move to FP[CS]R */ 2023 o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xee1<<16 | 0xa1<<4 2024 2025 o1 |= (uint32(p.From.Reg) & 15) << 12 2026 2027 case 57: /* move from FP[CS]R */ 2028 o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xef1<<16 | 0xa1<<4 2029 2030 o1 |= (uint32(p.To.Reg) & 15) << 12 2031 2032 case 58: /* movbu R,R */ 2033 o1 = c.oprrr(p, AAND, int(p.Scond)) 2034 2035 o1 |= uint32(immrot(0xff)) 2036 rt := int(p.To.Reg) 2037 r := int(p.From.Reg) 2038 if p.To.Type == obj.TYPE_NONE { 2039 rt = 0 2040 } 2041 if r == 0 { 2042 r = rt 2043 } 2044 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 2045 2046 case 59: /* movw/bu R<<I(R),R -> ldr indexed */ 2047 if p.From.Reg == 0 { 2048 c.ctxt.Diag("source operand is not a memory address: %v", p) 2049 break 2050 } 2051 if p.From.Offset&(1<<4) != 0 { 2052 c.ctxt.Diag("bad shift in LDR") 2053 break 2054 } 2055 o1 = c.olrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) 2056 if p.As == AMOVBU { 2057 o1 |= 1 << 22 2058 } 2059 2060 case 60: /* movb R(R),R -> ldrsb indexed */ 2061 if p.From.Reg == 0 { 2062 c.ctxt.Diag("source operand is not a memory address: %v", p) 2063 break 2064 } 2065 if p.From.Offset&(^0xf) != 0 { 2066 c.ctxt.Diag("bad shift: %v", p) 2067 break 2068 } 2069 o1 = c.olhrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) 2070 switch p.As { 2071 case AMOVB, AMOVBS: 2072 o1 ^= 1<<5 | 1<<6 2073 case AMOVH, AMOVHS: 2074 o1 ^= 1 << 6 2075 default: 2076 } 2077 if p.Scond&C_UBIT != 0 { 2078 o1 &^= 1 << 23 2079 } 2080 2081 case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ 2082 if p.To.Reg == 0 { 2083 c.ctxt.Diag("MOV to shifter operand") 2084 } 2085 o1 = c.osrr(int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond)) 2086 if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU { 2087 o1 |= 1 << 22 2088 } 2089 2090 case 62: /* MOVH/MOVHS/MOVHU Reg, Reg<<0(Reg) -> strh */ 2091 if p.To.Reg == 0 { 2092 c.ctxt.Diag("MOV to shifter operand") 2093 } 2094 if p.To.Offset&(^0xf) != 0 { 2095 c.ctxt.Diag("bad shift: %v", p) 2096 } 2097 o1 = c.olhrr(int(p.To.Offset), int(p.To.Reg), int(p.From.Reg), int(p.Scond)) 2098 o1 ^= 1 << 20 2099 if p.Scond&C_UBIT != 0 { 2100 o1 &^= 1 << 23 2101 } 2102 2103 /* reloc ops */ 2104 case 64: /* mov/movb/movbu R,addr */ 2105 o1 = c.omvl(p, &p.To, REGTMP) 2106 2107 if o1 == 0 { 2108 break 2109 } 2110 o2 = c.osr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond)) 2111 if o.flag&LPCREL != 0 { 2112 o3 = o2 2113 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2114 } 2115 2116 case 65: /* mov/movbu addr,R */ 2117 o1 = c.omvl(p, &p.From, REGTMP) 2118 2119 if o1 == 0 { 2120 break 2121 } 2122 o2 = c.olr(0, REGTMP, int(p.To.Reg), int(p.Scond)) 2123 if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { 2124 o2 |= 1 << 22 2125 } 2126 if o.flag&LPCREL != 0 { 2127 o3 = o2 2128 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2129 } 2130 2131 case 101: /* movw tlsvar,R, local exec*/ 2132 o1 = c.omvl(p, &p.From, int(p.To.Reg)) 2133 2134 case 102: /* movw tlsvar,R, initial exec*/ 2135 o1 = c.omvl(p, &p.From, int(p.To.Reg)) 2136 o2 = c.olrr(int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond)) 2137 2138 case 103: /* word tlsvar, local exec */ 2139 if p.To.Sym == nil { 2140 c.ctxt.Diag("nil sym in tls %v", p) 2141 } 2142 if p.To.Offset != 0 { 2143 c.ctxt.Diag("offset against tls var in %v", p) 2144 } 2145 // This case happens with words generated in the PC stream as part of 2146 // the literal c.pool. 2147 rel := obj.Addrel(c.cursym) 2148 2149 rel.Off = int32(c.pc) 2150 rel.Siz = 4 2151 rel.Sym = p.To.Sym 2152 rel.Type = objabi.R_TLS_LE 2153 o1 = 0 2154 2155 case 104: /* word tlsvar, initial exec */ 2156 if p.To.Sym == nil { 2157 c.ctxt.Diag("nil sym in tls %v", p) 2158 } 2159 if p.To.Offset != 0 { 2160 c.ctxt.Diag("offset against tls var in %v", p) 2161 } 2162 rel := obj.Addrel(c.cursym) 2163 rel.Off = int32(c.pc) 2164 rel.Siz = 4 2165 rel.Sym = p.To.Sym 2166 rel.Type = objabi.R_TLS_IE 2167 rel.Add = c.pc - p.Rel.Pc - 8 - int64(rel.Siz) 2168 2169 case 68: /* floating point store -> ADDR */ 2170 o1 = c.omvl(p, &p.To, REGTMP) 2171 2172 if o1 == 0 { 2173 break 2174 } 2175 o2 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p) 2176 if o.flag&LPCREL != 0 { 2177 o3 = o2 2178 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2179 } 2180 2181 case 69: /* floating point load <- ADDR */ 2182 o1 = c.omvl(p, &p.From, REGTMP) 2183 2184 if o1 == 0 { 2185 break 2186 } 2187 o2 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 2188 if o.flag&LPCREL != 0 { 2189 o3 = o2 2190 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2191 } 2192 2193 /* ArmV4 ops: */ 2194 case 70: /* movh/movhu R,O(R) -> strh */ 2195 c.aclass(&p.To) 2196 2197 r := int(p.To.Reg) 2198 if r == 0 { 2199 r = int(o.param) 2200 } 2201 o1 = c.oshr(int(p.From.Reg), int32(c.instoffset), r, int(p.Scond)) 2202 2203 case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ 2204 c.aclass(&p.From) 2205 2206 r := int(p.From.Reg) 2207 if r == 0 { 2208 r = int(o.param) 2209 } 2210 o1 = c.olhr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond)) 2211 if p.As == AMOVB || p.As == AMOVBS { 2212 o1 ^= 1<<5 | 1<<6 2213 } else if p.As == AMOVH || p.As == AMOVHS { 2214 o1 ^= (1 << 6) 2215 } 2216 2217 case 72: /* movh/movhu R,L(R) -> strh */ 2218 o1 = c.omvl(p, &p.To, REGTMP) 2219 2220 if o1 == 0 { 2221 break 2222 } 2223 r := int(p.To.Reg) 2224 if r == 0 { 2225 r = int(o.param) 2226 } 2227 o2 = c.oshrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond)) 2228 2229 case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ 2230 o1 = c.omvl(p, &p.From, REGTMP) 2231 2232 if o1 == 0 { 2233 break 2234 } 2235 r := int(p.From.Reg) 2236 if r == 0 { 2237 r = int(o.param) 2238 } 2239 o2 = c.olhrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond)) 2240 if p.As == AMOVB || p.As == AMOVBS { 2241 o2 ^= 1<<5 | 1<<6 2242 } else if p.As == AMOVH || p.As == AMOVHS { 2243 o2 ^= (1 << 6) 2244 } 2245 2246 case 74: /* bx $I */ 2247 c.ctxt.Diag("ABX $I") 2248 2249 case 75: /* bx O(R) */ 2250 c.aclass(&p.To) 2251 2252 if c.instoffset != 0 { 2253 c.ctxt.Diag("non-zero offset in ABX") 2254 } 2255 2256 /* 2257 o1 = c.oprrr(p, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR 2258 o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0); // BX R 2259 */ 2260 // p->to.reg may be REGLINK 2261 o1 = c.oprrr(p, AADD, int(p.Scond)) 2262 2263 o1 |= uint32(immrot(uint32(c.instoffset))) 2264 o1 |= (uint32(p.To.Reg) & 15) << 16 2265 o1 |= (REGTMP & 15) << 12 2266 o2 = c.oprrr(p, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR 2267 o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15 // BX Rtmp 2268 2269 case 76: /* bx O(R) when returning from fn*/ 2270 c.ctxt.Diag("ABXRET") 2271 2272 case 77: /* ldrex oreg,reg */ 2273 c.aclass(&p.From) 2274 2275 if c.instoffset != 0 { 2276 c.ctxt.Diag("offset must be zero in LDREX") 2277 } 2278 o1 = 0x19<<20 | 0xf9f 2279 o1 |= (uint32(p.From.Reg) & 15) << 16 2280 o1 |= (uint32(p.To.Reg) & 15) << 12 2281 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2282 2283 case 78: /* strex reg,oreg,reg */ 2284 c.aclass(&p.From) 2285 2286 if c.instoffset != 0 { 2287 c.ctxt.Diag("offset must be zero in STREX") 2288 } 2289 if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg { 2290 c.ctxt.Diag("cannot use same register as both source and destination: %v", p) 2291 } 2292 o1 = 0x18<<20 | 0xf90 2293 o1 |= (uint32(p.From.Reg) & 15) << 16 2294 o1 |= (uint32(p.Reg) & 15) << 0 2295 o1 |= (uint32(p.To.Reg) & 15) << 12 2296 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2297 2298 case 80: /* fmov zfcon,freg */ 2299 if p.As == AMOVD { 2300 o1 = 0xeeb00b00 // VMOV imm 64 2301 o2 = c.oprrr(p, ASUBD, int(p.Scond)) 2302 } else { 2303 o1 = 0x0eb00a00 // VMOV imm 32 2304 o2 = c.oprrr(p, ASUBF, int(p.Scond)) 2305 } 2306 2307 v := int32(0x70) // 1.0 2308 r := (int(p.To.Reg) & 15) << 0 2309 2310 // movf $1.0, r 2311 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2312 2313 o1 |= (uint32(r) & 15) << 12 2314 o1 |= (uint32(v) & 0xf) << 0 2315 o1 |= (uint32(v) & 0xf0) << 12 2316 2317 // subf r,r,r 2318 o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12 2319 2320 case 81: /* fmov sfcon,freg */ 2321 o1 = 0x0eb00a00 // VMOV imm 32 2322 if p.As == AMOVD { 2323 o1 = 0xeeb00b00 // VMOV imm 64 2324 } 2325 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2326 o1 |= (uint32(p.To.Reg) & 15) << 12 2327 v := int32(c.chipfloat5(p.From.Val.(float64))) 2328 o1 |= (uint32(v) & 0xf) << 0 2329 o1 |= (uint32(v) & 0xf0) << 12 2330 2331 case 82: /* fcmp freg,freg, */ 2332 o1 = c.oprrr(p, p.As, int(p.Scond)) 2333 2334 o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0 2335 o2 = 0x0ef1fa10 // VMRS R15 2336 o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2337 2338 case 83: /* fcmp freg,, */ 2339 o1 = c.oprrr(p, p.As, int(p.Scond)) 2340 2341 o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16 2342 o2 = 0x0ef1fa10 // VMRS R15 2343 o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2344 2345 case 84: /* movfw freg,freg - truncate float-to-fix */ 2346 o1 = c.oprrr(p, p.As, int(p.Scond)) 2347 2348 o1 |= (uint32(p.From.Reg) & 15) << 0 2349 o1 |= (uint32(p.To.Reg) & 15) << 12 2350 2351 case 85: /* movwf freg,freg - fix-to-float */ 2352 o1 = c.oprrr(p, p.As, int(p.Scond)) 2353 2354 o1 |= (uint32(p.From.Reg) & 15) << 0 2355 o1 |= (uint32(p.To.Reg) & 15) << 12 2356 2357 // macro for movfw freg,FTMP; movw FTMP,reg 2358 case 86: /* movfw freg,reg - truncate float-to-fix */ 2359 o1 = c.oprrr(p, p.As, int(p.Scond)) 2360 2361 o1 |= (uint32(p.From.Reg) & 15) << 0 2362 o1 |= (FREGTMP & 15) << 12 2363 o2 = c.oprrr(p, -AMOVFW, int(p.Scond)) 2364 o2 |= (FREGTMP & 15) << 16 2365 o2 |= (uint32(p.To.Reg) & 15) << 12 2366 2367 // macro for movw reg,FTMP; movwf FTMP,freg 2368 case 87: /* movwf reg,freg - fix-to-float */ 2369 o1 = c.oprrr(p, -AMOVWF, int(p.Scond)) 2370 2371 o1 |= (uint32(p.From.Reg) & 15) << 12 2372 o1 |= (FREGTMP & 15) << 16 2373 o2 = c.oprrr(p, p.As, int(p.Scond)) 2374 o2 |= (FREGTMP & 15) << 0 2375 o2 |= (uint32(p.To.Reg) & 15) << 12 2376 2377 case 88: /* movw reg,freg */ 2378 o1 = c.oprrr(p, -AMOVWF, int(p.Scond)) 2379 2380 o1 |= (uint32(p.From.Reg) & 15) << 12 2381 o1 |= (uint32(p.To.Reg) & 15) << 16 2382 2383 case 89: /* movw freg,reg */ 2384 o1 = c.oprrr(p, -AMOVFW, int(p.Scond)) 2385 2386 o1 |= (uint32(p.From.Reg) & 15) << 16 2387 o1 |= (uint32(p.To.Reg) & 15) << 12 2388 2389 case 91: /* ldrexd oreg,reg */ 2390 c.aclass(&p.From) 2391 2392 if c.instoffset != 0 { 2393 c.ctxt.Diag("offset must be zero in LDREX") 2394 } 2395 o1 = 0x1b<<20 | 0xf9f 2396 o1 |= (uint32(p.From.Reg) & 15) << 16 2397 o1 |= (uint32(p.To.Reg) & 15) << 12 2398 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2399 2400 case 92: /* strexd reg,oreg,reg */ 2401 c.aclass(&p.From) 2402 2403 if c.instoffset != 0 { 2404 c.ctxt.Diag("offset must be zero in STREX") 2405 } 2406 if p.Reg&1 != 0 { 2407 c.ctxt.Diag("source register must be even in STREXD: %v", p) 2408 } 2409 if p.To.Reg == p.From.Reg || p.To.Reg == p.Reg || p.To.Reg == p.Reg+1 { 2410 c.ctxt.Diag("cannot use same register as both source and destination: %v", p) 2411 } 2412 o1 = 0x1a<<20 | 0xf90 2413 o1 |= (uint32(p.From.Reg) & 15) << 16 2414 o1 |= (uint32(p.Reg) & 15) << 0 2415 o1 |= (uint32(p.To.Reg) & 15) << 12 2416 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2417 2418 case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ 2419 o1 = c.omvl(p, &p.From, REGTMP) 2420 2421 if o1 == 0 { 2422 break 2423 } 2424 o2 = c.olhr(0, REGTMP, int(p.To.Reg), int(p.Scond)) 2425 if p.As == AMOVB || p.As == AMOVBS { 2426 o2 ^= 1<<5 | 1<<6 2427 } else if p.As == AMOVH || p.As == AMOVHS { 2428 o2 ^= (1 << 6) 2429 } 2430 if o.flag&LPCREL != 0 { 2431 o3 = o2 2432 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2433 } 2434 2435 case 94: /* movh/movhu R,addr -> strh */ 2436 o1 = c.omvl(p, &p.To, REGTMP) 2437 2438 if o1 == 0 { 2439 break 2440 } 2441 o2 = c.oshr(int(p.From.Reg), 0, REGTMP, int(p.Scond)) 2442 if o.flag&LPCREL != 0 { 2443 o3 = o2 2444 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2445 } 2446 2447 case 95: /* PLD off(reg) */ 2448 o1 = 0xf5d0f000 2449 2450 o1 |= (uint32(p.From.Reg) & 15) << 16 2451 if p.From.Offset < 0 { 2452 o1 &^= (1 << 23) 2453 o1 |= uint32((-p.From.Offset) & 0xfff) 2454 } else { 2455 o1 |= uint32(p.From.Offset & 0xfff) 2456 } 2457 2458 // This is supposed to be something that stops execution. 2459 // It's not supposed to be reached, ever, but if it is, we'd 2460 // like to be able to tell how we got there. Assemble as 2461 // 0xf7fabcfd which is guaranteed to raise undefined instruction 2462 // exception. 2463 case 96: /* UNDEF */ 2464 o1 = 0xf7fabcfd 2465 2466 case 97: /* CLZ Rm, Rd */ 2467 o1 = c.oprrr(p, p.As, int(p.Scond)) 2468 2469 o1 |= (uint32(p.To.Reg) & 15) << 12 2470 o1 |= (uint32(p.From.Reg) & 15) << 0 2471 2472 case 98: /* MULW{T,B} Rs, Rm, Rd */ 2473 o1 = c.oprrr(p, p.As, int(p.Scond)) 2474 2475 o1 |= (uint32(p.To.Reg) & 15) << 16 2476 o1 |= (uint32(p.From.Reg) & 15) << 8 2477 o1 |= (uint32(p.Reg) & 15) << 0 2478 2479 case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ 2480 o1 = c.oprrr(p, p.As, int(p.Scond)) 2481 2482 o1 |= (uint32(p.To.Reg) & 15) << 16 2483 o1 |= (uint32(p.From.Reg) & 15) << 8 2484 o1 |= (uint32(p.Reg) & 15) << 0 2485 o1 |= uint32((p.To.Offset & 15) << 12) 2486 2487 case 105: /* divhw r,[r,]r */ 2488 o1 = c.oprrr(p, p.As, int(p.Scond)) 2489 rf := int(p.From.Reg) 2490 rt := int(p.To.Reg) 2491 r := int(p.Reg) 2492 if r == 0 { 2493 r = rt 2494 } 2495 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 2496 2497 case 110: /* dmb [mbop | $con] */ 2498 o1 = 0xf57ff050 2499 mbop := uint32(0) 2500 2501 switch c.aclass(&p.From) { 2502 case C_SPR: 2503 for _, f := range mbOp { 2504 if f.reg == p.From.Reg { 2505 mbop = f.enc 2506 break 2507 } 2508 } 2509 case C_RCON: 2510 for _, f := range mbOp { 2511 enc := uint32(c.instoffset) 2512 if f.enc == enc { 2513 mbop = enc 2514 break 2515 } 2516 } 2517 case C_NONE: 2518 mbop = 0xf 2519 } 2520 2521 if mbop == 0 { 2522 c.ctxt.Diag("illegal mb option:\n%v", p) 2523 } 2524 o1 |= mbop 2525 } 2526 2527 out[0] = o1 2528 out[1] = o2 2529 out[2] = o3 2530 out[3] = o4 2531 out[4] = o5 2532 out[5] = o6 2533 } 2534 2535 func (c *ctxt5) movxt(p *obj.Prog) uint32 { 2536 o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2537 switch p.As { 2538 case AMOVB, AMOVBS: 2539 o1 |= 0x6af<<16 | 0x7<<4 2540 case AMOVH, AMOVHS: 2541 o1 |= 0x6bf<<16 | 0x7<<4 2542 case AMOVBU: 2543 o1 |= 0x6ef<<16 | 0x7<<4 2544 case AMOVHU: 2545 o1 |= 0x6ff<<16 | 0x7<<4 2546 default: 2547 c.ctxt.Diag("illegal combination: %v", p) 2548 } 2549 switch p.From.Offset &^ 0xf { 2550 // only 0/8/16/24 bits rotation is accepted 2551 case SHIFT_RR, SHIFT_RR | 8<<7, SHIFT_RR | 16<<7, SHIFT_RR | 24<<7: 2552 o1 |= uint32(p.From.Offset) & 0xc0f 2553 default: 2554 c.ctxt.Diag("illegal shift: %v", p) 2555 } 2556 o1 |= (uint32(p.To.Reg) & 15) << 12 2557 return o1 2558 } 2559 2560 func (c *ctxt5) mov(p *obj.Prog) uint32 { 2561 c.aclass(&p.From) 2562 o1 := c.oprrr(p, p.As, int(p.Scond)) 2563 o1 |= uint32(p.From.Offset) 2564 rt := int(p.To.Reg) 2565 if p.To.Type == obj.TYPE_NONE { 2566 rt = 0 2567 } 2568 r := int(p.Reg) 2569 if p.As == AMOVW || p.As == AMVN { 2570 r = 0 2571 } else if r == 0 { 2572 r = rt 2573 } 2574 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 2575 return o1 2576 } 2577 2578 func (c *ctxt5) oprrr(p *obj.Prog, a obj.As, sc int) uint32 { 2579 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2580 if sc&C_SBIT != 0 { 2581 o |= 1 << 20 2582 } 2583 switch a { 2584 case ADIVHW: 2585 return o | 0x71<<20 | 0xf<<12 | 0x1<<4 2586 case ADIVUHW: 2587 return o | 0x73<<20 | 0xf<<12 | 0x1<<4 2588 case AMMUL: 2589 return o | 0x75<<20 | 0xf<<12 | 0x1<<4 2590 case AMULS: 2591 return o | 0x6<<20 | 0x9<<4 2592 case AMMULA: 2593 return o | 0x75<<20 | 0x1<<4 2594 case AMMULS: 2595 return o | 0x75<<20 | 0xd<<4 2596 case AMULU, AMUL: 2597 return o | 0x0<<21 | 0x9<<4 2598 case AMULA: 2599 return o | 0x1<<21 | 0x9<<4 2600 case AMULLU: 2601 return o | 0x4<<21 | 0x9<<4 2602 case AMULL: 2603 return o | 0x6<<21 | 0x9<<4 2604 case AMULALU: 2605 return o | 0x5<<21 | 0x9<<4 2606 case AMULAL: 2607 return o | 0x7<<21 | 0x9<<4 2608 case AAND: 2609 return o | 0x0<<21 2610 case AEOR: 2611 return o | 0x1<<21 2612 case ASUB: 2613 return o | 0x2<<21 2614 case ARSB: 2615 return o | 0x3<<21 2616 case AADD: 2617 return o | 0x4<<21 2618 case AADC: 2619 return o | 0x5<<21 2620 case ASBC: 2621 return o | 0x6<<21 2622 case ARSC: 2623 return o | 0x7<<21 2624 case ATST: 2625 return o | 0x8<<21 | 1<<20 2626 case ATEQ: 2627 return o | 0x9<<21 | 1<<20 2628 case ACMP: 2629 return o | 0xa<<21 | 1<<20 2630 case ACMN: 2631 return o | 0xb<<21 | 1<<20 2632 case AORR: 2633 return o | 0xc<<21 2634 2635 case AMOVB, AMOVH, AMOVW: 2636 if sc&(C_PBIT|C_WBIT) != 0 { 2637 c.ctxt.Diag("invalid .P/.W suffix: %v", p) 2638 } 2639 return o | 0xd<<21 2640 case ABIC: 2641 return o | 0xe<<21 2642 case AMVN: 2643 return o | 0xf<<21 2644 case ASLL: 2645 return o | 0xd<<21 | 0<<5 2646 case ASRL: 2647 return o | 0xd<<21 | 1<<5 2648 case ASRA: 2649 return o | 0xd<<21 | 2<<5 2650 case ASWI: 2651 return o | 0xf<<24 2652 2653 case AADDD: 2654 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4 2655 case AADDF: 2656 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4 2657 case ASUBD: 2658 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4 2659 case ASUBF: 2660 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4 2661 case AMULD: 2662 return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4 2663 case AMULF: 2664 return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4 2665 case ANMULD: 2666 return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0x4<<4 2667 case ANMULF: 2668 return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0x4<<4 2669 case AMULAD: 2670 return o | 0xe<<24 | 0xb<<8 2671 case AMULAF: 2672 return o | 0xe<<24 | 0xa<<8 2673 case AMULSD: 2674 return o | 0xe<<24 | 0xb<<8 | 0x4<<4 2675 case AMULSF: 2676 return o | 0xe<<24 | 0xa<<8 | 0x4<<4 2677 case ANMULAD: 2678 return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 0x4<<4 2679 case ANMULAF: 2680 return o | 0xe<<24 | 0x1<<20 | 0xa<<8 | 0x4<<4 2681 case ANMULSD: 2682 return o | 0xe<<24 | 0x1<<20 | 0xb<<8 2683 case ANMULSF: 2684 return o | 0xe<<24 | 0x1<<20 | 0xa<<8 2685 case AFMULAD: 2686 return o | 0xe<<24 | 0xa<<20 | 0xb<<8 2687 case AFMULAF: 2688 return o | 0xe<<24 | 0xa<<20 | 0xa<<8 2689 case AFMULSD: 2690 return o | 0xe<<24 | 0xa<<20 | 0xb<<8 | 0x4<<4 2691 case AFMULSF: 2692 return o | 0xe<<24 | 0xa<<20 | 0xa<<8 | 0x4<<4 2693 case AFNMULAD: 2694 return o | 0xe<<24 | 0x9<<20 | 0xb<<8 | 0x4<<4 2695 case AFNMULAF: 2696 return o | 0xe<<24 | 0x9<<20 | 0xa<<8 | 0x4<<4 2697 case AFNMULSD: 2698 return o | 0xe<<24 | 0x9<<20 | 0xb<<8 2699 case AFNMULSF: 2700 return o | 0xe<<24 | 0x9<<20 | 0xa<<8 2701 case ADIVD: 2702 return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4 2703 case ADIVF: 2704 return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4 2705 case ASQRTD: 2706 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4 2707 case ASQRTF: 2708 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4 2709 case AABSD: 2710 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4 2711 case AABSF: 2712 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4 2713 case ANEGD: 2714 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0x4<<4 2715 case ANEGF: 2716 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0x4<<4 2717 case ACMPD: 2718 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4 2719 case ACMPF: 2720 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4 2721 2722 case AMOVF: 2723 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4 2724 case AMOVD: 2725 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4 2726 2727 case AMOVDF: 2728 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof 2729 case AMOVFD: 2730 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof 2731 2732 case AMOVWF: 2733 if sc&C_UBIT == 0 { 2734 o |= 1 << 7 /* signed */ 2735 } 2736 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double 2737 2738 case AMOVWD: 2739 if sc&C_UBIT == 0 { 2740 o |= 1 << 7 /* signed */ 2741 } 2742 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double 2743 2744 case AMOVFW: 2745 if sc&C_UBIT == 0 { 2746 o |= 1 << 16 /* signed */ 2747 } 2748 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc 2749 2750 case AMOVDW: 2751 if sc&C_UBIT == 0 { 2752 o |= 1 << 16 /* signed */ 2753 } 2754 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc 2755 2756 case -AMOVWF: // copy WtoF 2757 return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4 2758 2759 case -AMOVFW: // copy FtoW 2760 return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4 2761 2762 case -ACMP: // cmp imm 2763 return o | 0x3<<24 | 0x5<<20 2764 2765 case ABFX: 2766 return o | 0x3d<<21 | 0x5<<4 2767 2768 case ABFXU: 2769 return o | 0x3f<<21 | 0x5<<4 2770 2771 case ABFC: 2772 return o | 0x3e<<21 | 0x1f 2773 2774 case ABFI: 2775 return o | 0x3e<<21 | 0x1<<4 2776 2777 case AXTAB: 2778 return o | 0x6a<<20 | 0x7<<4 2779 2780 case AXTAH: 2781 return o | 0x6b<<20 | 0x7<<4 2782 2783 case AXTABU: 2784 return o | 0x6e<<20 | 0x7<<4 2785 2786 case AXTAHU: 2787 return o | 0x6f<<20 | 0x7<<4 2788 2789 // CLZ doesn't support .nil 2790 case ACLZ: 2791 return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4 2792 2793 case AREV: 2794 return o&(0xf<<28) | 0x6bf<<16 | 0xf3<<4 2795 2796 case AREV16: 2797 return o&(0xf<<28) | 0x6bf<<16 | 0xfb<<4 2798 2799 case AREVSH: 2800 return o&(0xf<<28) | 0x6ff<<16 | 0xfb<<4 2801 2802 case ARBIT: 2803 return o&(0xf<<28) | 0x6ff<<16 | 0xf3<<4 2804 2805 case AMULWT: 2806 return o&(0xf<<28) | 0x12<<20 | 0xe<<4 2807 2808 case AMULWB: 2809 return o&(0xf<<28) | 0x12<<20 | 0xa<<4 2810 2811 case AMULBB: 2812 return o&(0xf<<28) | 0x16<<20 | 0x8<<4 2813 2814 case AMULAWT: 2815 return o&(0xf<<28) | 0x12<<20 | 0xc<<4 2816 2817 case AMULAWB: 2818 return o&(0xf<<28) | 0x12<<20 | 0x8<<4 2819 2820 case AMULABB: 2821 return o&(0xf<<28) | 0x10<<20 | 0x8<<4 2822 2823 case ABL: // BLX REG 2824 return o&(0xf<<28) | 0x12fff3<<4 2825 } 2826 2827 c.ctxt.Diag("%v: bad rrr %d", p, a) 2828 return 0 2829 } 2830 2831 func (c *ctxt5) opbra(p *obj.Prog, a obj.As, sc int) uint32 { 2832 sc &= C_SCOND 2833 sc ^= C_SCOND_XOR 2834 if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY { 2835 return uint32(sc)<<28 | 0x5<<25 | 0x1<<24 2836 } 2837 if sc != 0xe { 2838 c.ctxt.Diag("%v: .COND on bcond instruction", p) 2839 } 2840 switch a { 2841 case ABEQ: 2842 return 0x0<<28 | 0x5<<25 2843 case ABNE: 2844 return 0x1<<28 | 0x5<<25 2845 case ABCS: 2846 return 0x2<<28 | 0x5<<25 2847 case ABHS: 2848 return 0x2<<28 | 0x5<<25 2849 case ABCC: 2850 return 0x3<<28 | 0x5<<25 2851 case ABLO: 2852 return 0x3<<28 | 0x5<<25 2853 case ABMI: 2854 return 0x4<<28 | 0x5<<25 2855 case ABPL: 2856 return 0x5<<28 | 0x5<<25 2857 case ABVS: 2858 return 0x6<<28 | 0x5<<25 2859 case ABVC: 2860 return 0x7<<28 | 0x5<<25 2861 case ABHI: 2862 return 0x8<<28 | 0x5<<25 2863 case ABLS: 2864 return 0x9<<28 | 0x5<<25 2865 case ABGE: 2866 return 0xa<<28 | 0x5<<25 2867 case ABLT: 2868 return 0xb<<28 | 0x5<<25 2869 case ABGT: 2870 return 0xc<<28 | 0x5<<25 2871 case ABLE: 2872 return 0xd<<28 | 0x5<<25 2873 case AB: 2874 return 0xe<<28 | 0x5<<25 2875 } 2876 2877 c.ctxt.Diag("%v: bad bra %v", p, a) 2878 return 0 2879 } 2880 2881 func (c *ctxt5) olr(v int32, b int, r int, sc int) uint32 { 2882 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2883 if sc&C_PBIT == 0 { 2884 o |= 1 << 24 2885 } 2886 if sc&C_UBIT == 0 { 2887 o |= 1 << 23 2888 } 2889 if sc&C_WBIT != 0 { 2890 o |= 1 << 21 2891 } 2892 o |= 1<<26 | 1<<20 2893 if v < 0 { 2894 if sc&C_UBIT != 0 { 2895 c.ctxt.Diag(".U on neg offset") 2896 } 2897 v = -v 2898 o ^= 1 << 23 2899 } 2900 2901 if v >= 1<<12 || v < 0 { 2902 c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp) 2903 } 2904 o |= uint32(v) 2905 o |= (uint32(b) & 15) << 16 2906 o |= (uint32(r) & 15) << 12 2907 return o 2908 } 2909 2910 func (c *ctxt5) olhr(v int32, b int, r int, sc int) uint32 { 2911 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2912 if sc&C_PBIT == 0 { 2913 o |= 1 << 24 2914 } 2915 if sc&C_WBIT != 0 { 2916 o |= 1 << 21 2917 } 2918 o |= 1<<23 | 1<<20 | 0xb<<4 2919 if v < 0 { 2920 v = -v 2921 o ^= 1 << 23 2922 } 2923 2924 if v >= 1<<8 || v < 0 { 2925 c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp) 2926 } 2927 o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22 2928 o |= (uint32(b) & 15) << 16 2929 o |= (uint32(r) & 15) << 12 2930 return o 2931 } 2932 2933 func (c *ctxt5) osr(a obj.As, r int, v int32, b int, sc int) uint32 { 2934 o := c.olr(v, b, r, sc) ^ (1 << 20) 2935 if a != AMOVW { 2936 o |= 1 << 22 2937 } 2938 return o 2939 } 2940 2941 func (c *ctxt5) oshr(r int, v int32, b int, sc int) uint32 { 2942 o := c.olhr(v, b, r, sc) ^ (1 << 20) 2943 return o 2944 } 2945 2946 func (c *ctxt5) osrr(r int, i int, b int, sc int) uint32 { 2947 return c.olr(int32(i), b, r, sc) ^ (1<<25 | 1<<20) 2948 } 2949 2950 func (c *ctxt5) oshrr(r int, i int, b int, sc int) uint32 { 2951 return c.olhr(int32(i), b, r, sc) ^ (1<<22 | 1<<20) 2952 } 2953 2954 func (c *ctxt5) olrr(i int, b int, r int, sc int) uint32 { 2955 return c.olr(int32(i), b, r, sc) ^ (1 << 25) 2956 } 2957 2958 func (c *ctxt5) olhrr(i int, b int, r int, sc int) uint32 { 2959 return c.olhr(int32(i), b, r, sc) ^ (1 << 22) 2960 } 2961 2962 func (c *ctxt5) ofsr(a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 { 2963 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2964 if sc&C_PBIT == 0 { 2965 o |= 1 << 24 2966 } 2967 if sc&C_WBIT != 0 { 2968 o |= 1 << 21 2969 } 2970 o |= 6<<25 | 1<<24 | 1<<23 | 10<<8 2971 if v < 0 { 2972 v = -v 2973 o ^= 1 << 23 2974 } 2975 2976 if v&3 != 0 { 2977 c.ctxt.Diag("odd offset for floating point op: %d\n%v", v, p) 2978 } else if v >= 1<<10 || v < 0 { 2979 c.ctxt.Diag("literal span too large: %d\n%v", v, p) 2980 } 2981 o |= (uint32(v) >> 2) & 0xFF 2982 o |= (uint32(b) & 15) << 16 2983 o |= (uint32(r) & 15) << 12 2984 2985 switch a { 2986 default: 2987 c.ctxt.Diag("bad fst %v", a) 2988 fallthrough 2989 2990 case AMOVD: 2991 o |= 1 << 8 2992 fallthrough 2993 2994 case AMOVF: 2995 break 2996 } 2997 2998 return o 2999 } 3000 3001 // MOVW $"lower 16-bit", Reg 3002 func (c *ctxt5) omvs(p *obj.Prog, a *obj.Addr, dr int) uint32 { 3003 o1 := ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 3004 o1 |= 0x30 << 20 3005 o1 |= (uint32(dr) & 15) << 12 3006 o1 |= uint32(a.Offset) & 0x0fff 3007 o1 |= (uint32(a.Offset) & 0xf000) << 4 3008 return o1 3009 } 3010 3011 // MVN $C_NCON, Reg -> MOVW $C_RCON, Reg 3012 func (c *ctxt5) omvr(p *obj.Prog, a *obj.Addr, dr int) uint32 { 3013 o1 := c.oprrr(p, AMOVW, int(p.Scond)) 3014 o1 |= (uint32(dr) & 15) << 12 3015 v := immrot(^uint32(a.Offset)) 3016 if v == 0 { 3017 c.ctxt.Diag("%v: missing literal", p) 3018 return 0 3019 } 3020 o1 |= uint32(v) 3021 return o1 3022 } 3023 3024 func (c *ctxt5) omvl(p *obj.Prog, a *obj.Addr, dr int) uint32 { 3025 var o1 uint32 3026 if p.Pool == nil { 3027 c.aclass(a) 3028 v := immrot(^uint32(c.instoffset)) 3029 if v == 0 { 3030 c.ctxt.Diag("%v: missing literal", p) 3031 return 0 3032 } 3033 3034 o1 = c.oprrr(p, AMVN, int(p.Scond)&C_SCOND) 3035 o1 |= uint32(v) 3036 o1 |= (uint32(dr) & 15) << 12 3037 } else { 3038 v := int32(p.Pool.Pc - p.Pc - 8) 3039 o1 = c.olr(v, REGPC, dr, int(p.Scond)&C_SCOND) 3040 } 3041 3042 return o1 3043 } 3044 3045 func (c *ctxt5) chipzero5(e float64) int { 3046 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 3047 if objabi.GOARM < 7 || math.Float64bits(e) != 0 { 3048 return -1 3049 } 3050 return 0 3051 } 3052 3053 func (c *ctxt5) chipfloat5(e float64) int { 3054 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 3055 if objabi.GOARM < 7 { 3056 return -1 3057 } 3058 3059 ei := math.Float64bits(e) 3060 l := uint32(ei) 3061 h := uint32(ei >> 32) 3062 3063 if l != 0 || h&0xffff != 0 { 3064 return -1 3065 } 3066 h1 := h & 0x7fc00000 3067 if h1 != 0x40000000 && h1 != 0x3fc00000 { 3068 return -1 3069 } 3070 n := 0 3071 3072 // sign bit (a) 3073 if h&0x80000000 != 0 { 3074 n |= 1 << 7 3075 } 3076 3077 // exp sign bit (b) 3078 if h1 == 0x3fc00000 { 3079 n |= 1 << 6 3080 } 3081 3082 // rest of exp and mantissa (cd-efgh) 3083 n |= int((h >> 16) & 0x3f) 3084 3085 //print("match %.8lux %.8lux %d\n", l, h, n); 3086 return n 3087 } 3088 3089 func nocache(p *obj.Prog) { 3090 p.Optab = 0 3091 p.From.Class = 0 3092 if p.GetFrom3() != nil { 3093 p.GetFrom3().Class = 0 3094 } 3095 p.To.Class = 0 3096 }