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