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