github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/liblink/asm5.c (about) 1 // Inferno utils/5l/span.c 2 // http://code.google.com/p/inferno-os/source/browse/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 // Instruction layout. 32 33 #include <u.h> 34 #include <libc.h> 35 #include <bio.h> 36 #include <link.h> 37 #include "../cmd/5l/5.out.h" 38 #include "../runtime/stack.h" 39 40 typedef struct Optab Optab; 41 typedef struct Oprang Oprang; 42 typedef uchar Opcross[32][2][32]; 43 44 struct Optab 45 { 46 uchar as; 47 uchar a1; 48 char a2; 49 uchar a3; 50 uchar type; 51 char size; 52 char param; 53 char flag; 54 uchar pcrelsiz; 55 }; 56 struct Oprang 57 { 58 Optab* start; 59 Optab* stop; 60 }; 61 62 enum 63 { 64 LFROM = 1<<0, 65 LTO = 1<<1, 66 LPOOL = 1<<2, 67 LPCREL = 1<<3, 68 }; 69 70 static Optab optab[] = 71 { 72 /* struct Optab: 73 OPCODE, from, prog->reg, to, type,size,param,flag */ 74 { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 }, 75 { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 }, 76 77 { AADD, C_REG, C_REG, C_REG, 1, 4, 0 }, 78 { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 }, 79 { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 }, 80 { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 }, 81 { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 }, 82 83 { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 }, 84 { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 }, 85 { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 }, 86 { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 }, 87 { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 }, 88 89 { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 }, 90 { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, 91 { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, 92 { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 }, 93 94 { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP }, 95 96 { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL }, 97 { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, 98 { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 }, 99 { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, 100 101 { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL }, 102 { ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0 }, 103 { ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0 }, 104 { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 }, 105 { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 }, 106 107 { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 }, 108 { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 }, 109 110 { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 }, 111 { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 }, 112 113 { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 }, 114 { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 }, 115 { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 }, 116 117 { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 }, 118 { AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0 }, 119 { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 }, 120 121 { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 }, 122 { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM }, 123 { AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4}, 124 125 { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 }, 126 { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 }, 127 { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 }, 128 { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 }, 129 { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM }, 130 { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, 131 { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, 132 { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM }, 133 134 { AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0 }, 135 { AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0 }, 136 { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 }, 137 { AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0 }, 138 { AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0 }, 139 { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 }, 140 141 { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 }, 142 { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 }, 143 144 { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 }, 145 { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 }, 146 147 { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 }, 148 { AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0 }, 149 150 { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, 151 { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, 152 { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, 153 { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, 154 { AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, 155 { AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, 156 { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, 157 { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, 158 159 { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, 160 { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, 161 { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, 162 { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, 163 164 { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, 165 { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, 166 { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, 167 { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, 168 { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, 169 { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, 170 { AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, 171 { AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, 172 { AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, 173 { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, 174 { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, 175 { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, 176 177 { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, 178 { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, 179 { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 }, 180 { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, 181 { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, 182 { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 }, 183 184 { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM }, 185 186 { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 }, 187 { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 }, 188 { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 }, 189 190 { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 }, 191 { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 }, 192 193 { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 }, 194 195 { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 }, 196 197 { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP }, 198 { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 }, 199 200 { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP }, 201 { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 }, 202 203 { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO }, 204 { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO }, 205 206 { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM }, 207 { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM }, 208 209 { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4 }, 210 { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4}, 211 212 { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, 213 { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 }, 214 { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, 215 216 { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 }, 217 { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 }, 218 219 { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, 220 { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, 221 222 { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 }, 223 { AMOVBS, C_SHIFT,C_NONE, C_REG, 60, 4, 0 }, 224 225 { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, 226 { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, 227 { AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, 228 { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, 229 230 { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 }, 231 { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, LPCREL, 0 }, 232 233 { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, 234 { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, 235 { AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, 236 { AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, 237 { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, 238 { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, 239 240 { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, 241 { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, 242 { AMOVBS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, 243 { AMOVBS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, 244 { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, 245 { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, 246 { AMOVHS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, 247 { AMOVHS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, 248 { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, 249 { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, 250 251 { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, 252 { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, 253 { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, 254 { AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, 255 { AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, 256 { AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, 257 { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, 258 { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, 259 { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, 260 261 { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, 262 { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, 263 { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, 264 { AMOVBS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, 265 { AMOVBS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, 266 { AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, 267 { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, 268 { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, 269 { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, 270 { AMOVHS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, 271 { AMOVHS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, 272 { AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, 273 { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, 274 { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, 275 { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, 276 277 { ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 }, 278 { ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 }, 279 280 { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 8, 0 }, 281 { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 }, 282 283 { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 }, 284 { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 }, 285 286 { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 }, 287 { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 }, 288 289 { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 }, 290 { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 }, 291 292 { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 }, 293 { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 }, 294 295 { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 }, 296 297 { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 }, 298 { ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 }, 299 300 { APLD, C_SOREG,C_NONE, C_NONE, 95, 4, 0 }, 301 302 { AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0 }, 303 304 { ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0 }, 305 306 { AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 }, 307 { AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 }, 308 309 { AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 }, 310 { APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0 }, 311 { AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0 }, 312 { ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0 }, 313 314 { ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, // same as ABL 315 { ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, // same as ABL 316 317 { ADATABUNDLE, C_NONE, C_NONE, C_NONE, 100, 4, 0 }, 318 { ADATABUNDLEEND, C_NONE, C_NONE, C_NONE, 100, 0, 0 }, 319 320 { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, 321 }; 322 323 static struct { 324 uint32 start; 325 uint32 size; 326 uint32 extra; 327 } pool; 328 329 static int checkpool(Link*, Prog*, int); 330 static int flushpool(Link*, Prog*, int, int); 331 static void addpool(Link*, Prog*, Addr*); 332 static void asmout(Link*, Prog*, Optab*, int32*); 333 static int asmoutnacl(Link*, int32, Prog*, Optab*, int32 *); 334 static Optab* oplook(Link*, Prog*); 335 static int32 oprrr(Link*, int, int); 336 static int32 olr(Link*, int32, int, int, int); 337 static int32 olhr(Link*, int32, int, int, int); 338 static int32 olrr(Link*, int, int, int, int); 339 static int32 olhrr(Link*, int, int, int, int); 340 static int32 osr(Link*, int, int, int32, int, int); 341 static int32 oshr(Link*, int, int32, int, int); 342 static int32 ofsr(Link*, int, int, int32, int, int, Prog*); 343 static int32 osrr(Link*, int, int, int, int); 344 static int32 oshrr(Link*, int, int, int, int); 345 static int32 omvl(Link*, Prog*, Addr*, int); 346 static int32 immaddr(int32); 347 static int aclass(Link*, Addr*); 348 static int32 immrot(uint32); 349 static int32 immaddr(int32); 350 static int32 opbra(Link*, int, int); 351 352 static Oprang oprange[ALAST]; 353 static uchar xcmp[C_GOK+1][C_GOK+1]; 354 355 static Prog zprg = { 356 .as = AGOK, 357 .scond = C_SCOND_NONE, 358 .reg = NREG, 359 .from = { 360 .name = D_NONE, 361 .type = D_NONE, 362 .reg = NREG, 363 }, 364 .to = { 365 .name = D_NONE, 366 .type = D_NONE, 367 .reg = NREG, 368 }, 369 }; 370 371 static LSym *deferreturn; 372 373 static void 374 nocache(Prog *p) 375 { 376 p->optab = 0; 377 p->from.class = 0; 378 p->to.class = 0; 379 } 380 381 /* size of a case statement including jump table */ 382 static int32 383 casesz(Link *ctxt, Prog *p) 384 { 385 int jt = 0; 386 int32 n = 0; 387 Optab *o; 388 389 for( ; p != nil; p = p->link){ 390 if(p->as == ABCASE) 391 jt = 1; 392 else if(jt) 393 break; 394 o = oplook(ctxt, p); 395 n += o->size; 396 } 397 return n; 398 } 399 400 static void buildop(Link*); 401 402 // asmoutnacl assembles the instruction p. It replaces asmout for NaCl. 403 // It returns the total number of bytes put in out, and it can change 404 // p->pc if extra padding is necessary. 405 // In rare cases, asmoutnacl might split p into two instructions. 406 // origPC is the PC for this Prog (no padding is taken into account). 407 static int 408 asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, int32 *out) 409 { 410 int size, reg; 411 Prog *q; 412 Addr *a, *a2; 413 414 size = o->size; 415 416 // instruction specific 417 switch(p->as) { 418 default: 419 if(out != nil) 420 asmout(ctxt, p, o, out); 421 break; 422 case ADATABUNDLE: // align to 16-byte boundary 423 case ADATABUNDLEEND: // zero width instruction, just to align next instruction to 16-byte boundary 424 p->pc = (p->pc+15) & ~15; 425 if(out != nil) 426 asmout(ctxt, p, o, out); 427 break; 428 case AUNDEF: 429 case APLD: 430 size = 4; 431 if(out != nil) { 432 switch(p->as) { 433 case AUNDEF: 434 out[0] = 0xe7fedef0; // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0) 435 break; 436 case APLD: 437 out[0] = 0xe1a01001; // (MOVW R1, R1) 438 break; 439 } 440 } 441 break; 442 case AB: 443 case ABL: 444 if(p->to.type != D_OREG) { 445 if(out != nil) 446 asmout(ctxt, p, o, out); 447 } else { 448 if(p->to.offset != 0 || size != 4 || p->to.reg >= 16 || p->to.reg < 0) 449 ctxt->diag("unsupported instruction: %P", p); 450 if((p->pc&15) == 12) 451 p->pc += 4; 452 if(out != nil) { 453 out[0] = ((p->scond&C_SCOND)<<28) | 0x03c0013f | (p->to.reg << 12) | (p->to.reg << 16); // BIC $0xc000000f, Rx 454 if(p->as == AB) 455 out[1] = ((p->scond&C_SCOND)<<28) | 0x012fff10 | p->to.reg; // BX Rx 456 else // ABL 457 out[1] = ((p->scond&C_SCOND)<<28) | 0x012fff30 | p->to.reg; // BLX Rx 458 } 459 size = 8; 460 } 461 // align the last instruction (the actual BL) to the last instruction in a bundle 462 if(p->as == ABL) { 463 if(deferreturn == nil) 464 deferreturn = linklookup(ctxt, "runtime.deferreturn", 0); 465 if(p->to.sym == deferreturn) 466 p->pc = ((origPC+15) & ~15) + 16 - size; 467 else 468 p->pc += (16 - ((p->pc+size)&15)) & 15; 469 } 470 break; 471 case ALDREX: 472 case ALDREXD: 473 case AMOVB: 474 case AMOVBS: 475 case AMOVBU: 476 case AMOVD: 477 case AMOVF: 478 case AMOVH: 479 case AMOVHS: 480 case AMOVHU: 481 case AMOVM: 482 case AMOVW: 483 case ASTREX: 484 case ASTREXD: 485 if(p->to.type == D_REG && p->to.reg == 15 && p->from.reg == 13) { // MOVW.W x(R13), PC 486 if(out != nil) 487 asmout(ctxt, p, o, out); 488 if(size == 4) { 489 if(out != nil) { 490 // Note: 5c and 5g reg.c know that DIV/MOD smashes R12 491 // so that this return instruction expansion is valid. 492 out[0] = out[0] & ~0x3000; // change PC to R12 493 out[1] = ((p->scond&C_SCOND)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12 494 out[2] = ((p->scond&C_SCOND)<<28) | 0x012fff1c; // BX R12 495 } 496 size += 8; 497 if(((p->pc+size) & 15) == 4) 498 p->pc += 4; 499 break; 500 } else { 501 // if the instruction used more than 4 bytes, then it must have used a very large 502 // offset to update R13, so we need to additionally mask R13. 503 if(out != nil) { 504 out[size/4-1] &= ~0x3000; // change PC to R12 505 out[size/4] = ((p->scond&C_SCOND)<<28) | 0x03cdd103; // BIC $0xc0000000, R13 506 out[size/4+1] = ((p->scond&C_SCOND)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12 507 out[size/4+2] = ((p->scond&C_SCOND)<<28) | 0x012fff1c; // BX R12 508 } 509 // p->pc+size is only ok at 4 or 12 mod 16. 510 if((p->pc+size)%8 == 0) 511 p->pc += 4; 512 size += 12; 513 break; 514 } 515 } 516 517 if(p->to.type == D_REG && p->to.reg == 15) 518 ctxt->diag("unsupported instruction (move to another register and use indirect jump instead): %P", p); 519 520 if(p->to.type == D_OREG && p->to.reg == 13 && (p->scond & C_WBIT) && size > 4) { 521 // function prolog with very large frame size: MOVW.W R14,-100004(R13) 522 // split it into two instructions: 523 // ADD $-100004, R13 524 // MOVW R14, 0(R13) 525 q = ctxt->arch->prg(); 526 p->scond &= ~C_WBIT; 527 *q = *p; 528 a = &p->to; 529 if(p->to.type == D_OREG) 530 a2 = &q->to; 531 else 532 a2 = &q->from; 533 nocache(q); 534 nocache(p); 535 // insert q after p 536 q->link = p->link; 537 p->link = q; 538 q->pcond = nil; 539 // make p into ADD $X, R13 540 p->as = AADD; 541 p->from = *a; 542 p->from.reg = NREG; 543 p->from.type = D_CONST; 544 p->to = zprg.to; 545 p->to.type = D_REG; 546 p->to.reg = 13; 547 // make q into p but load/store from 0(R13) 548 q->spadj = 0; 549 *a2 = zprg.from; 550 a2->type = D_OREG; 551 a2->reg = 13; 552 a2->sym = nil; 553 a2->offset = 0; 554 size = oplook(ctxt, p)->size; 555 break; 556 } 557 558 if((p->to.type == D_OREG && p->to.reg != 13 && p->to.reg != 9) || // MOVW Rx, X(Ry), y != 13 && y != 9 559 (p->from.type == D_OREG && p->from.reg != 13 && p->from.reg != 9)) { // MOVW X(Rx), Ry, x != 13 && x != 9 560 if(p->to.type == D_OREG) 561 a = &p->to; 562 else 563 a = &p->from; 564 reg = a->reg; 565 if(size == 4) { 566 // if addr.reg == NREG, then it is probably load from x(FP) with small x, no need to modify. 567 if(reg == NREG) { 568 if(out != nil) 569 asmout(ctxt, p, o, out); 570 } else { 571 if(out != nil) 572 out[0] = ((p->scond&C_SCOND)<<28) | 0x03c00103 | (reg << 16) | (reg << 12); // BIC $0xc0000000, Rx 573 if((p->pc&15) == 12) 574 p->pc += 4; 575 size += 4; 576 if(out != nil) 577 asmout(ctxt, p, o, &out[1]); 578 } 579 break; 580 } else { 581 // if a load/store instruction takes more than 1 word to implement, then 582 // we need to seperate the instruction into two: 583 // 1. explicitly load the address into R11. 584 // 2. load/store from R11. 585 // This won't handle .W/.P, so we should reject such code. 586 if(p->scond & (C_PBIT|C_WBIT)) 587 ctxt->diag("unsupported instruction (.P/.W): %P", p); 588 q = ctxt->arch->prg(); 589 *q = *p; 590 if(p->to.type == D_OREG) 591 a2 = &q->to; 592 else 593 a2 = &q->from; 594 nocache(q); 595 nocache(p); 596 // insert q after p 597 q->link = p->link; 598 p->link = q; 599 q->pcond = nil; 600 // make p into MOVW $X(R), R11 601 p->as = AMOVW; 602 p->from = *a; 603 p->from.type = D_CONST; 604 p->to = zprg.to; 605 p->to.type = D_REG; 606 p->to.reg = 11; 607 // make q into p but load/store from 0(R11) 608 *a2 = zprg.from; 609 a2->type = D_OREG; 610 a2->reg = 11; 611 a2->sym = nil; 612 a2->offset = 0; 613 size = oplook(ctxt, p)->size; 614 break; 615 } 616 } else if(out != nil) 617 asmout(ctxt, p, o, out); 618 break; 619 } 620 621 // destination register specific 622 if(p->to.type == D_REG) { 623 switch(p->to.reg) { 624 case 9: 625 ctxt->diag("invalid instruction, cannot write to R9: %P", p); 626 break; 627 case 13: 628 if(out != nil) 629 out[size/4] = 0xe3cdd103; // BIC $0xc0000000, R13 630 if(((p->pc+size) & 15) == 0) 631 p->pc += 4; 632 size += 4; 633 break; 634 } 635 } 636 return size; 637 } 638 639 void 640 span5(Link *ctxt, LSym *cursym) 641 { 642 Prog *p, *op; 643 Optab *o; 644 int m, bflag, i, v, times; 645 int32 c, opc, out[6+3]; 646 uchar *bp; 647 648 p = cursym->text; 649 if(p == nil || p->link == nil) // handle external functions and ELF section symbols 650 return; 651 652 if(oprange[AAND].start == nil) 653 buildop(ctxt); 654 655 ctxt->cursym = cursym; 656 657 ctxt->autosize = p->to.offset + 4; 658 c = 0; 659 660 for(op = p, p = p->link; p != nil || ctxt->blitrl != nil; op = p, p = p->link) { 661 if(p == nil) { 662 if(checkpool(ctxt, op, 0)) { 663 p = op; 664 continue; 665 } 666 // can't happen: blitrl is not nil, but checkpool didn't flushpool 667 ctxt->diag("internal inconsistency"); 668 break; 669 } 670 ctxt->curp = p; 671 p->pc = c; 672 o = oplook(ctxt, p); 673 if(ctxt->headtype != Hnacl) { 674 m = o->size; 675 } else { 676 m = asmoutnacl(ctxt, c, p, o, nil); 677 c = p->pc; // asmoutnacl might change pc for alignment 678 o = oplook(ctxt, p); // asmoutnacl might change p in rare cases 679 } 680 if(m % 4 != 0 || p->pc % 4 != 0) { 681 ctxt->diag("!pc invalid: %P size=%d", p, m); 682 } 683 // must check literal pool here in case p generates many instructions 684 if(ctxt->blitrl){ 685 if(checkpool(ctxt, op, p->as == ACASE ? casesz(ctxt, p) : m)) { 686 p = op; 687 continue; 688 } 689 } 690 if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA && p->as != ADATABUNDLEEND && p->as != ANOP)) { 691 ctxt->diag("zero-width instruction\n%P", p); 692 continue; 693 } 694 switch(o->flag & (LFROM|LTO|LPOOL)) { 695 case LFROM: 696 addpool(ctxt, p, &p->from); 697 break; 698 case LTO: 699 addpool(ctxt, p, &p->to); 700 break; 701 case LPOOL: 702 if ((p->scond&C_SCOND) == C_SCOND_NONE) 703 flushpool(ctxt, p, 0, 0); 704 break; 705 } 706 if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == C_SCOND_NONE) 707 flushpool(ctxt, p, 0, 0); 708 c += m; 709 } 710 cursym->size = c; 711 712 /* 713 * if any procedure is large enough to 714 * generate a large SBRA branch, then 715 * generate extra passes putting branches 716 * around jmps to fix. this is rare. 717 */ 718 times = 0; 719 do { 720 if(ctxt->debugvlog) 721 Bprint(ctxt->bso, "%5.2f span1\n", cputime()); 722 bflag = 0; 723 c = 0; 724 times++; 725 cursym->text->pc = 0; // force re-layout the code. 726 for(p = cursym->text; p != nil; p = p->link) { 727 ctxt->curp = p; 728 o = oplook(ctxt,p); 729 if(c > p->pc) 730 p->pc = c; 731 /* very large branches 732 if(o->type == 6 && p->pcond) { 733 otxt = p->pcond->pc - c; 734 if(otxt < 0) 735 otxt = -otxt; 736 if(otxt >= (1L<<17) - 10) { 737 q = ctxt->arch->prg(); 738 q->link = p->link; 739 p->link = q; 740 q->as = AB; 741 q->to.type = D_BRANCH; 742 q->pcond = p->pcond; 743 p->pcond = q; 744 q = ctxt->arch->prg(); 745 q->link = p->link; 746 p->link = q; 747 q->as = AB; 748 q->to.type = D_BRANCH; 749 q->pcond = q->link->link; 750 bflag = 1; 751 } 752 } 753 */ 754 opc = p->pc; 755 if(ctxt->headtype != Hnacl) 756 m = o->size; 757 else 758 m = asmoutnacl(ctxt, c, p, o, nil); 759 if(p->pc != opc) { 760 bflag = 1; 761 //print("%P pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times); 762 } 763 c = p->pc + m; 764 if(m % 4 != 0 || p->pc % 4 != 0) { 765 ctxt->diag("pc invalid: %P size=%d", p, m); 766 } 767 if(m/4 > nelem(out)) 768 ctxt->diag("instruction size too large: %d > %d", m/4, nelem(out)); 769 if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA && p->as != ADATABUNDLEEND && p->as != ANOP)) { 770 if(p->as == ATEXT) { 771 ctxt->autosize = p->to.offset + 4; 772 continue; 773 } 774 ctxt->diag("zero-width instruction\n%P", p); 775 continue; 776 } 777 } 778 cursym->size = c; 779 } while(bflag); 780 if(c % 4 != 0) { 781 ctxt->diag("sym->size=%d, invalid", c); 782 } 783 784 /* 785 * lay out the code. all the pc-relative code references, 786 * even cross-function, are resolved now; 787 * only data references need to be relocated. 788 * with more work we could leave cross-function 789 * code references to be relocated too, and then 790 * perhaps we'd be able to parallelize the span loop above. 791 */ 792 if(ctxt->tlsg == nil) 793 ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0); 794 795 p = cursym->text; 796 ctxt->autosize = p->to.offset + 4; 797 symgrow(ctxt, cursym, cursym->size); 798 799 bp = cursym->p; 800 c = p->pc; // even p->link might need extra padding 801 for(p = p->link; p != nil; p = p->link) { 802 ctxt->pc = p->pc; 803 ctxt->curp = p; 804 o = oplook(ctxt, p); 805 opc = p->pc; 806 if(ctxt->headtype != Hnacl) { 807 asmout(ctxt, p, o, out); 808 m = o->size; 809 } else { 810 m = asmoutnacl(ctxt, c, p, o, out); 811 if(opc != p->pc) 812 ctxt->diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %P", opc, (int32)p->pc, p); 813 } 814 if(m % 4 != 0 || p->pc % 4 != 0) { 815 ctxt->diag("final stage: pc invalid: %P size=%d", p, m); 816 } 817 if(c > p->pc) 818 ctxt->diag("PC padding invalid: want %#lld, has %#d: %P", p->pc, c, p); 819 while(c != p->pc) { 820 // emit 0xe1a00000 (MOVW R0, R0) 821 *bp++ = 0x00; 822 *bp++ = 0x00; 823 *bp++ = 0xa0; 824 *bp++ = 0xe1; 825 c += 4; 826 } 827 for(i=0; i<m/4; i++) { 828 v = out[i]; 829 *bp++ = v; 830 *bp++ = v>>8; 831 *bp++ = v>>16; 832 *bp++ = v>>24; 833 } 834 c += m; 835 } 836 } 837 838 /* 839 * when the first reference to the literal pool threatens 840 * to go out of range of a 12-bit PC-relative offset, 841 * drop the pool now, and branch round it. 842 * this happens only in extended basic blocks that exceed 4k. 843 */ 844 static int 845 checkpool(Link *ctxt, Prog *p, int sz) 846 { 847 if(pool.size >= 0xff0 || immaddr((p->pc+sz+4)+4+(12+pool.size) - (pool.start+8)) == 0) 848 return flushpool(ctxt, p, 1, 0); 849 else if(p->link == nil) 850 return flushpool(ctxt, p, 2, 0); 851 return 0; 852 } 853 854 static int 855 flushpool(Link *ctxt, Prog *p, int skip, int force) 856 { 857 Prog *q; 858 859 if(ctxt->blitrl) { 860 if(skip){ 861 if(0 && skip==1)print("note: flush literal pool at %llux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start); 862 q = ctxt->arch->prg(); 863 q->as = AB; 864 q->to.type = D_BRANCH; 865 q->pcond = p->link; 866 q->link = ctxt->blitrl; 867 q->lineno = p->lineno; 868 ctxt->blitrl = q; 869 } 870 else if(!force && (p->pc+(12+pool.size)-pool.start < 2048)) // 12 take into account the maximum nacl literal pool alignment padding size 871 return 0; 872 if(ctxt->headtype == Hnacl && pool.size % 16 != 0) { 873 // if pool is not multiple of 16 bytes, add an alignment marker 874 q = ctxt->arch->prg(); 875 q->as = ADATABUNDLEEND; 876 ctxt->elitrl->link = q; 877 ctxt->elitrl = q; 878 } 879 ctxt->elitrl->link = p->link; 880 p->link = ctxt->blitrl; 881 // BUG(minux): how to correctly handle line number for constant pool entries? 882 // for now, we set line number to the last instruction preceding them at least 883 // this won't bloat the .debug_line tables 884 while(ctxt->blitrl) { 885 ctxt->blitrl->lineno = p->lineno; 886 ctxt->blitrl = ctxt->blitrl->link; 887 } 888 ctxt->blitrl = 0; /* BUG: should refer back to values until out-of-range */ 889 ctxt->elitrl = 0; 890 pool.size = 0; 891 pool.start = 0; 892 pool.extra = 0; 893 return 1; 894 } 895 return 0; 896 } 897 898 static void 899 addpool(Link *ctxt, Prog *p, Addr *a) 900 { 901 Prog *q, t; 902 int c; 903 904 c = aclass(ctxt, a); 905 906 t = zprg; 907 t.as = AWORD; 908 909 switch(c) { 910 default: 911 t.to.offset = a->offset; 912 t.to.sym = a->sym; 913 t.to.type = a->type; 914 t.to.name = a->name; 915 916 if(ctxt->flag_shared && t.to.sym != nil) 917 t.pcrel = p; 918 break; 919 920 case C_SROREG: 921 case C_LOREG: 922 case C_ROREG: 923 case C_FOREG: 924 case C_SOREG: 925 case C_HOREG: 926 case C_FAUTO: 927 case C_SAUTO: 928 case C_LAUTO: 929 case C_LACON: 930 t.to.type = D_CONST; 931 t.to.offset = ctxt->instoffset; 932 break; 933 } 934 935 if(t.pcrel == nil) { 936 for(q = ctxt->blitrl; q != nil; q = q->link) /* could hash on t.t0.offset */ 937 if(q->pcrel == nil && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) { 938 p->pcond = q; 939 return; 940 } 941 } 942 943 if(ctxt->headtype == Hnacl && pool.size%16 == 0) { 944 // start a new data bundle 945 q = ctxt->arch->prg(); 946 *q = zprg; 947 q->as = ADATABUNDLE; 948 q->pc = pool.size; 949 pool.size += 4; 950 if(ctxt->blitrl == nil) { 951 ctxt->blitrl = q; 952 pool.start = p->pc; 953 } else { 954 ctxt->elitrl->link = q; 955 } 956 ctxt->elitrl = q; 957 } 958 959 q = ctxt->arch->prg(); 960 *q = t; 961 q->pc = pool.size; 962 963 if(ctxt->blitrl == nil) { 964 ctxt->blitrl = q; 965 pool.start = p->pc; 966 } else 967 ctxt->elitrl->link = q; 968 ctxt->elitrl = q; 969 pool.size += 4; 970 971 p->pcond = q; 972 } 973 974 static int32 975 regoff(Link *ctxt, Addr *a) 976 { 977 978 ctxt->instoffset = 0; 979 aclass(ctxt, a); 980 return ctxt->instoffset; 981 } 982 983 static int32 984 immrot(uint32 v) 985 { 986 int i; 987 988 for(i=0; i<16; i++) { 989 if((v & ~0xff) == 0) 990 return (i<<8) | v | (1<<25); 991 v = (v<<2) | (v>>30); 992 } 993 return 0; 994 } 995 996 static int32 997 immaddr(int32 v) 998 { 999 if(v >= 0 && v <= 0xfff) 1000 return (v & 0xfff) | 1001 (1<<24) | /* pre indexing */ 1002 (1<<23); /* pre indexing, up */ 1003 if(v >= -0xfff && v < 0) 1004 return (-v & 0xfff) | 1005 (1<<24); /* pre indexing */ 1006 return 0; 1007 } 1008 1009 static int 1010 immfloat(int32 v) 1011 { 1012 return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */ 1013 } 1014 1015 static int 1016 immhalf(int32 v) 1017 { 1018 if(v >= 0 && v <= 0xff) 1019 return v| 1020 (1<<24)| /* pre indexing */ 1021 (1<<23); /* pre indexing, up */ 1022 if(v >= -0xff && v < 0) 1023 return (-v & 0xff)| 1024 (1<<24); /* pre indexing */ 1025 return 0; 1026 } 1027 1028 static int aconsize(Link *ctxt); 1029 1030 static int 1031 aclass(Link *ctxt, Addr *a) 1032 { 1033 LSym *s; 1034 int t; 1035 1036 switch(a->type) { 1037 case D_NONE: 1038 return C_NONE; 1039 1040 case D_REG: 1041 return C_REG; 1042 1043 case D_REGREG: 1044 return C_REGREG; 1045 1046 case D_REGREG2: 1047 return C_REGREG2; 1048 1049 case D_SHIFT: 1050 return C_SHIFT; 1051 1052 case D_FREG: 1053 return C_FREG; 1054 1055 case D_FPCR: 1056 return C_FCR; 1057 1058 case D_OREG: 1059 switch(a->name) { 1060 case D_EXTERN: 1061 case D_STATIC: 1062 if(a->sym == 0 || a->sym->name == 0) { 1063 print("null sym external\n"); 1064 return C_GOK; 1065 } 1066 ctxt->instoffset = 0; // s.b. unused but just in case 1067 return C_ADDR; 1068 1069 case D_AUTO: 1070 ctxt->instoffset = ctxt->autosize + a->offset; 1071 t = immaddr(ctxt->instoffset); 1072 if(t){ 1073 if(immhalf(ctxt->instoffset)) 1074 return immfloat(t) ? C_HFAUTO : C_HAUTO; 1075 if(immfloat(t)) 1076 return C_FAUTO; 1077 return C_SAUTO; 1078 } 1079 return C_LAUTO; 1080 1081 case D_PARAM: 1082 ctxt->instoffset = ctxt->autosize + a->offset + 4L; 1083 t = immaddr(ctxt->instoffset); 1084 if(t){ 1085 if(immhalf(ctxt->instoffset)) 1086 return immfloat(t) ? C_HFAUTO : C_HAUTO; 1087 if(immfloat(t)) 1088 return C_FAUTO; 1089 return C_SAUTO; 1090 } 1091 return C_LAUTO; 1092 case D_NONE: 1093 ctxt->instoffset = a->offset; 1094 t = immaddr(ctxt->instoffset); 1095 if(t) { 1096 if(immhalf(ctxt->instoffset)) /* n.b. that it will also satisfy immrot */ 1097 return immfloat(t) ? C_HFOREG : C_HOREG; 1098 if(immfloat(t)) 1099 return C_FOREG; /* n.b. that it will also satisfy immrot */ 1100 t = immrot(ctxt->instoffset); 1101 if(t) 1102 return C_SROREG; 1103 if(immhalf(ctxt->instoffset)) 1104 return C_HOREG; 1105 return C_SOREG; 1106 } 1107 t = immrot(ctxt->instoffset); 1108 if(t) 1109 return C_ROREG; 1110 return C_LOREG; 1111 } 1112 return C_GOK; 1113 1114 case D_PSR: 1115 return C_PSR; 1116 1117 case D_OCONST: 1118 switch(a->name) { 1119 case D_EXTERN: 1120 case D_STATIC: 1121 ctxt->instoffset = 0; // s.b. unused but just in case 1122 return C_ADDR; 1123 } 1124 return C_GOK; 1125 1126 case D_FCONST: 1127 if(chipzero5(ctxt, a->u.dval) >= 0) 1128 return C_ZFCON; 1129 if(chipfloat5(ctxt, a->u.dval) >= 0) 1130 return C_SFCON; 1131 return C_LFCON; 1132 1133 case D_CONST: 1134 case D_CONST2: 1135 switch(a->name) { 1136 1137 case D_NONE: 1138 ctxt->instoffset = a->offset; 1139 if(a->reg != NREG) 1140 return aconsize(ctxt); 1141 1142 t = immrot(ctxt->instoffset); 1143 if(t) 1144 return C_RCON; 1145 t = immrot(~ctxt->instoffset); 1146 if(t) 1147 return C_NCON; 1148 return C_LCON; 1149 1150 case D_EXTERN: 1151 case D_STATIC: 1152 s = a->sym; 1153 if(s == nil) 1154 break; 1155 ctxt->instoffset = 0; // s.b. unused but just in case 1156 return C_LCONADDR; 1157 1158 case D_AUTO: 1159 ctxt->instoffset = ctxt->autosize + a->offset; 1160 return aconsize(ctxt); 1161 1162 case D_PARAM: 1163 ctxt->instoffset = ctxt->autosize + a->offset + 4L; 1164 return aconsize(ctxt); 1165 } 1166 return C_GOK; 1167 1168 case D_BRANCH: 1169 return C_SBRA; 1170 } 1171 return C_GOK; 1172 } 1173 1174 static int 1175 aconsize(Link *ctxt) 1176 { 1177 int t; 1178 1179 t = immrot(ctxt->instoffset); 1180 if(t) 1181 return C_RACON; 1182 return C_LACON; 1183 } 1184 1185 static void 1186 prasm(Prog *p) 1187 { 1188 print("%P\n", p); 1189 } 1190 1191 static Optab* 1192 oplook(Link *ctxt, Prog *p) 1193 { 1194 int a1, a2, a3, r; 1195 uchar *c1, *c3; 1196 Optab *o, *e; 1197 1198 a1 = p->optab; 1199 if(a1) 1200 return optab+(a1-1); 1201 a1 = p->from.class; 1202 if(a1 == 0) { 1203 a1 = aclass(ctxt, &p->from) + 1; 1204 p->from.class = a1; 1205 } 1206 a1--; 1207 a3 = p->to.class; 1208 if(a3 == 0) { 1209 a3 = aclass(ctxt, &p->to) + 1; 1210 p->to.class = a3; 1211 } 1212 a3--; 1213 a2 = C_NONE; 1214 if(p->reg != NREG) 1215 a2 = C_REG; 1216 r = p->as; 1217 o = oprange[r].start; 1218 if(o == 0) { 1219 o = oprange[r].stop; /* just generate an error */ 1220 } 1221 if(0 /*debug['O']*/) { 1222 print("oplook %A %^ %^ %^\n", 1223 (int)p->as, a1, a2, a3); 1224 print(" %d %d\n", p->from.type, p->to.type); 1225 } 1226 e = oprange[r].stop; 1227 c1 = xcmp[a1]; 1228 c3 = xcmp[a3]; 1229 for(; o<e; o++) 1230 if(o->a2 == a2) 1231 if(c1[o->a1]) 1232 if(c3[o->a3]) { 1233 p->optab = (o-optab)+1; 1234 return o; 1235 } 1236 ctxt->diag("illegal combination %P; %^ %^ %^, %d %d", 1237 p, a1, a2, a3, p->from.type, p->to.type); 1238 ctxt->diag("from %d %d to %d %d\n", p->from.type, p->from.name, p->to.type, p->to.name); 1239 prasm(p); 1240 if(o == 0) 1241 o = optab; 1242 return o; 1243 } 1244 1245 static int 1246 cmp(int a, int b) 1247 { 1248 1249 if(a == b) 1250 return 1; 1251 switch(a) { 1252 case C_LCON: 1253 if(b == C_RCON || b == C_NCON) 1254 return 1; 1255 break; 1256 case C_LACON: 1257 if(b == C_RACON) 1258 return 1; 1259 break; 1260 case C_LFCON: 1261 if(b == C_ZFCON || b == C_SFCON) 1262 return 1; 1263 break; 1264 1265 case C_HFAUTO: 1266 return b == C_HAUTO || b == C_FAUTO; 1267 case C_FAUTO: 1268 case C_HAUTO: 1269 return b == C_HFAUTO; 1270 case C_SAUTO: 1271 return cmp(C_HFAUTO, b); 1272 case C_LAUTO: 1273 return cmp(C_SAUTO, b); 1274 1275 case C_HFOREG: 1276 return b == C_HOREG || b == C_FOREG; 1277 case C_FOREG: 1278 case C_HOREG: 1279 return b == C_HFOREG; 1280 case C_SROREG: 1281 return cmp(C_SOREG, b) || cmp(C_ROREG, b); 1282 case C_SOREG: 1283 case C_ROREG: 1284 return b == C_SROREG || cmp(C_HFOREG, b); 1285 case C_LOREG: 1286 return cmp(C_SROREG, b); 1287 1288 case C_LBRA: 1289 if(b == C_SBRA) 1290 return 1; 1291 break; 1292 1293 case C_HREG: 1294 return cmp(C_SP, b) || cmp(C_PC, b); 1295 1296 } 1297 return 0; 1298 } 1299 1300 static int 1301 ocmp(const void *a1, const void *a2) 1302 { 1303 Optab *p1, *p2; 1304 int n; 1305 1306 p1 = (Optab*)a1; 1307 p2 = (Optab*)a2; 1308 n = p1->as - p2->as; 1309 if(n) 1310 return n; 1311 n = p1->a1 - p2->a1; 1312 if(n) 1313 return n; 1314 n = p1->a2 - p2->a2; 1315 if(n) 1316 return n; 1317 n = p1->a3 - p2->a3; 1318 if(n) 1319 return n; 1320 return 0; 1321 } 1322 1323 static void 1324 buildop(Link *ctxt) 1325 { 1326 int i, n, r; 1327 1328 for(i=0; i<C_GOK; i++) 1329 for(n=0; n<C_GOK; n++) 1330 xcmp[i][n] = cmp(n, i); 1331 for(n=0; optab[n].as != AXXX; n++) { 1332 if((optab[n].flag & LPCREL) != 0) { 1333 if(ctxt->flag_shared) 1334 optab[n].size += optab[n].pcrelsiz; 1335 else 1336 optab[n].flag &= ~LPCREL; 1337 } 1338 } 1339 qsort(optab, n, sizeof(optab[0]), ocmp); 1340 for(i=0; i<n; i++) { 1341 r = optab[i].as; 1342 oprange[r].start = optab+i; 1343 while(optab[i].as == r) 1344 i++; 1345 oprange[r].stop = optab+i; 1346 i--; 1347 1348 switch(r) 1349 { 1350 default: 1351 ctxt->diag("unknown op in build: %A", r); 1352 sysfatal("bad code"); 1353 case AADD: 1354 oprange[AAND] = oprange[r]; 1355 oprange[AEOR] = oprange[r]; 1356 oprange[ASUB] = oprange[r]; 1357 oprange[ARSB] = oprange[r]; 1358 oprange[AADC] = oprange[r]; 1359 oprange[ASBC] = oprange[r]; 1360 oprange[ARSC] = oprange[r]; 1361 oprange[AORR] = oprange[r]; 1362 oprange[ABIC] = oprange[r]; 1363 break; 1364 case ACMP: 1365 oprange[ATEQ] = oprange[r]; 1366 oprange[ACMN] = oprange[r]; 1367 break; 1368 case AMVN: 1369 break; 1370 case ABEQ: 1371 oprange[ABNE] = oprange[r]; 1372 oprange[ABCS] = oprange[r]; 1373 oprange[ABHS] = oprange[r]; 1374 oprange[ABCC] = oprange[r]; 1375 oprange[ABLO] = oprange[r]; 1376 oprange[ABMI] = oprange[r]; 1377 oprange[ABPL] = oprange[r]; 1378 oprange[ABVS] = oprange[r]; 1379 oprange[ABVC] = oprange[r]; 1380 oprange[ABHI] = oprange[r]; 1381 oprange[ABLS] = oprange[r]; 1382 oprange[ABGE] = oprange[r]; 1383 oprange[ABLT] = oprange[r]; 1384 oprange[ABGT] = oprange[r]; 1385 oprange[ABLE] = oprange[r]; 1386 break; 1387 case ASLL: 1388 oprange[ASRL] = oprange[r]; 1389 oprange[ASRA] = oprange[r]; 1390 break; 1391 case AMUL: 1392 oprange[AMULU] = oprange[r]; 1393 break; 1394 case ADIV: 1395 oprange[AMOD] = oprange[r]; 1396 oprange[AMODU] = oprange[r]; 1397 oprange[ADIVU] = oprange[r]; 1398 break; 1399 case AMOVW: 1400 case AMOVB: 1401 case AMOVBS: 1402 case AMOVBU: 1403 case AMOVH: 1404 case AMOVHS: 1405 case AMOVHU: 1406 break; 1407 case ASWPW: 1408 oprange[ASWPBU] = oprange[r]; 1409 break; 1410 case AB: 1411 case ABL: 1412 case ABX: 1413 case ABXRET: 1414 case ADUFFZERO: 1415 case ADUFFCOPY: 1416 case ASWI: 1417 case AWORD: 1418 case AMOVM: 1419 case ARFE: 1420 case ATEXT: 1421 case AUSEFIELD: 1422 case ACASE: 1423 case ABCASE: 1424 case ATYPE: 1425 break; 1426 case AADDF: 1427 oprange[AADDD] = oprange[r]; 1428 oprange[ASUBF] = oprange[r]; 1429 oprange[ASUBD] = oprange[r]; 1430 oprange[AMULF] = oprange[r]; 1431 oprange[AMULD] = oprange[r]; 1432 oprange[ADIVF] = oprange[r]; 1433 oprange[ADIVD] = oprange[r]; 1434 oprange[ASQRTF] = oprange[r]; 1435 oprange[ASQRTD] = oprange[r]; 1436 oprange[AMOVFD] = oprange[r]; 1437 oprange[AMOVDF] = oprange[r]; 1438 oprange[AABSF] = oprange[r]; 1439 oprange[AABSD] = oprange[r]; 1440 break; 1441 1442 case ACMPF: 1443 oprange[ACMPD] = oprange[r]; 1444 break; 1445 1446 case AMOVF: 1447 oprange[AMOVD] = oprange[r]; 1448 break; 1449 1450 case AMOVFW: 1451 oprange[AMOVDW] = oprange[r]; 1452 break; 1453 1454 case AMOVWF: 1455 oprange[AMOVWD] = oprange[r]; 1456 break; 1457 1458 case AMULL: 1459 oprange[AMULAL] = oprange[r]; 1460 oprange[AMULLU] = oprange[r]; 1461 oprange[AMULALU] = oprange[r]; 1462 break; 1463 1464 case AMULWT: 1465 oprange[AMULWB] = oprange[r]; 1466 break; 1467 1468 case AMULAWT: 1469 oprange[AMULAWB] = oprange[r]; 1470 break; 1471 1472 case AMULA: 1473 case ALDREX: 1474 case ASTREX: 1475 case ALDREXD: 1476 case ASTREXD: 1477 case ATST: 1478 case APLD: 1479 case AUNDEF: 1480 case ACLZ: 1481 case AFUNCDATA: 1482 case APCDATA: 1483 case ANOP: 1484 case ADATABUNDLE: 1485 case ADATABUNDLEEND: 1486 break; 1487 } 1488 } 1489 } 1490 1491 static int32 mov(Link*, Prog*); 1492 1493 static void 1494 asmout(Link *ctxt, Prog *p, Optab *o, int32 *out) 1495 { 1496 int32 o1, o2, o3, o4, o5, o6, v; 1497 int r, rf, rt, rt2; 1498 Reloc *rel; 1499 1500 ctxt->printp = p; 1501 o1 = 0; 1502 o2 = 0; 1503 o3 = 0; 1504 o4 = 0; 1505 o5 = 0; 1506 o6 = 0; 1507 ctxt->armsize += o->size; 1508 if(0 /*debug['P']*/) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type); 1509 switch(o->type) { 1510 default: 1511 ctxt->diag("unknown asm %d", o->type); 1512 prasm(p); 1513 break; 1514 1515 case 0: /* pseudo ops */ 1516 if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr); 1517 break; 1518 1519 case 1: /* op R,[R],R */ 1520 o1 = oprrr(ctxt, p->as, p->scond); 1521 rf = p->from.reg; 1522 rt = p->to.reg; 1523 r = p->reg; 1524 if(p->to.type == D_NONE) 1525 rt = 0; 1526 if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN) 1527 r = 0; 1528 else 1529 if(r == NREG) 1530 r = rt; 1531 o1 |= rf | (r<<16) | (rt<<12); 1532 break; 1533 1534 case 2: /* movbu $I,[R],R */ 1535 aclass(ctxt, &p->from); 1536 o1 = oprrr(ctxt, p->as, p->scond); 1537 o1 |= immrot(ctxt->instoffset); 1538 rt = p->to.reg; 1539 r = p->reg; 1540 if(p->to.type == D_NONE) 1541 rt = 0; 1542 if(p->as == AMOVW || p->as == AMVN) 1543 r = 0; 1544 else if(r == NREG) 1545 r = rt; 1546 o1 |= (r<<16) | (rt<<12); 1547 break; 1548 1549 case 3: /* add R<<[IR],[R],R */ 1550 o1 = mov(ctxt, p); 1551 break; 1552 1553 case 4: /* add $I,[R],R */ 1554 aclass(ctxt, &p->from); 1555 o1 = oprrr(ctxt, AADD, p->scond); 1556 o1 |= immrot(ctxt->instoffset); 1557 r = p->from.reg; 1558 if(r == NREG) 1559 r = o->param; 1560 o1 |= r << 16; 1561 o1 |= p->to.reg << 12; 1562 break; 1563 1564 case 5: /* bra s */ 1565 o1 = opbra(ctxt, p->as, p->scond); 1566 v = -8; 1567 if(p->to.sym != nil) { 1568 rel = addrel(ctxt->cursym); 1569 rel->off = ctxt->pc; 1570 rel->siz = 4; 1571 rel->sym = p->to.sym; 1572 v += p->to.offset; 1573 rel->add = o1 | ((v >> 2) & 0xffffff); 1574 rel->type = R_CALLARM; 1575 break; 1576 } 1577 if(p->pcond != nil) 1578 v = (p->pcond->pc - ctxt->pc) - 8; 1579 o1 |= (v >> 2) & 0xffffff; 1580 break; 1581 1582 case 6: /* b ,O(R) -> add $O,R,PC */ 1583 aclass(ctxt, &p->to); 1584 o1 = oprrr(ctxt, AADD, p->scond); 1585 o1 |= immrot(ctxt->instoffset); 1586 o1 |= p->to.reg << 16; 1587 o1 |= REGPC << 12; 1588 break; 1589 1590 case 7: /* bl (R) -> blx R */ 1591 aclass(ctxt, &p->to); 1592 if(ctxt->instoffset != 0) 1593 ctxt->diag("%P: doesn't support BL offset(REG) where offset != 0", p); 1594 o1 = oprrr(ctxt, ABL, p->scond); 1595 o1 |= p->to.reg; 1596 rel = addrel(ctxt->cursym); 1597 rel->off = ctxt->pc; 1598 rel->siz = 0; 1599 rel->type = R_CALLIND; 1600 break; 1601 1602 case 8: /* sll $c,[R],R -> mov (R<<$c),R */ 1603 aclass(ctxt, &p->from); 1604 o1 = oprrr(ctxt, p->as, p->scond); 1605 r = p->reg; 1606 if(r == NREG) 1607 r = p->to.reg; 1608 o1 |= r; 1609 o1 |= (ctxt->instoffset&31) << 7; 1610 o1 |= p->to.reg << 12; 1611 break; 1612 1613 case 9: /* sll R,[R],R -> mov (R<<R),R */ 1614 o1 = oprrr(ctxt, p->as, p->scond); 1615 r = p->reg; 1616 if(r == NREG) 1617 r = p->to.reg; 1618 o1 |= r; 1619 o1 |= (p->from.reg << 8) | (1<<4); 1620 o1 |= p->to.reg << 12; 1621 break; 1622 1623 case 10: /* swi [$con] */ 1624 o1 = oprrr(ctxt, p->as, p->scond); 1625 if(p->to.type != D_NONE) { 1626 aclass(ctxt, &p->to); 1627 o1 |= ctxt->instoffset & 0xffffff; 1628 } 1629 break; 1630 1631 case 11: /* word */ 1632 aclass(ctxt, &p->to); 1633 o1 = ctxt->instoffset; 1634 if(p->to.sym != nil) { 1635 // This case happens with words generated 1636 // in the PC stream as part of the literal pool. 1637 rel = addrel(ctxt->cursym); 1638 rel->off = ctxt->pc; 1639 rel->siz = 4; 1640 rel->sym = p->to.sym; 1641 rel->add = p->to.offset; 1642 1643 // runtime.tlsg is special. 1644 // Its "address" is the offset from the TLS thread pointer 1645 // to the thread-local g and m pointers. 1646 // Emit a TLS relocation instead of a standard one. 1647 if(rel->sym == ctxt->tlsg) { 1648 rel->type = R_TLS; 1649 if(ctxt->flag_shared) 1650 rel->add += ctxt->pc - p->pcrel->pc - 8 - rel->siz; 1651 rel->xadd = rel->add; 1652 rel->xsym = rel->sym; 1653 } else if(ctxt->flag_shared) { 1654 rel->type = R_PCREL; 1655 rel->add += ctxt->pc - p->pcrel->pc - 8; 1656 } else 1657 rel->type = R_ADDR; 1658 o1 = 0; 1659 } 1660 break; 1661 1662 case 12: /* movw $lcon, reg */ 1663 o1 = omvl(ctxt, p, &p->from, p->to.reg); 1664 if(o->flag & LPCREL) { 1665 o2 = oprrr(ctxt, AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12; 1666 } 1667 break; 1668 1669 case 13: /* op $lcon, [R], R */ 1670 o1 = omvl(ctxt, p, &p->from, REGTMP); 1671 if(!o1) 1672 break; 1673 o2 = oprrr(ctxt, p->as, p->scond); 1674 o2 |= REGTMP; 1675 r = p->reg; 1676 if(p->as == AMOVW || p->as == AMVN) 1677 r = 0; 1678 else if(r == NREG) 1679 r = p->to.reg; 1680 o2 |= r << 16; 1681 if(p->to.type != D_NONE) 1682 o2 |= p->to.reg << 12; 1683 break; 1684 1685 case 14: /* movb/movbu/movh/movhu R,R */ 1686 o1 = oprrr(ctxt, ASLL, p->scond); 1687 1688 if(p->as == AMOVBU || p->as == AMOVHU) 1689 o2 = oprrr(ctxt, ASRL, p->scond); 1690 else 1691 o2 = oprrr(ctxt, ASRA, p->scond); 1692 1693 r = p->to.reg; 1694 o1 |= (p->from.reg)|(r<<12); 1695 o2 |= (r)|(r<<12); 1696 if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) { 1697 o1 |= (24<<7); 1698 o2 |= (24<<7); 1699 } else { 1700 o1 |= (16<<7); 1701 o2 |= (16<<7); 1702 } 1703 break; 1704 1705 case 15: /* mul r,[r,]r */ 1706 o1 = oprrr(ctxt, p->as, p->scond); 1707 rf = p->from.reg; 1708 rt = p->to.reg; 1709 r = p->reg; 1710 if(r == NREG) 1711 r = rt; 1712 if(rt == r) { 1713 r = rf; 1714 rf = rt; 1715 } 1716 if(0) 1717 if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) { 1718 ctxt->diag("bad registers in MUL"); 1719 prasm(p); 1720 } 1721 o1 |= (rf<<8) | r | (rt<<16); 1722 break; 1723 1724 1725 case 16: /* div r,[r,]r */ 1726 o1 = 0xf << 28; 1727 o2 = 0; 1728 break; 1729 1730 case 17: 1731 o1 = oprrr(ctxt, p->as, p->scond); 1732 rf = p->from.reg; 1733 rt = p->to.reg; 1734 rt2 = p->to.offset; 1735 r = p->reg; 1736 o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12); 1737 break; 1738 1739 case 20: /* mov/movb/movbu R,O(R) */ 1740 aclass(ctxt, &p->to); 1741 r = p->to.reg; 1742 if(r == NREG) 1743 r = o->param; 1744 o1 = osr(ctxt, p->as, p->from.reg, ctxt->instoffset, r, p->scond); 1745 break; 1746 1747 case 21: /* mov/movbu O(R),R -> lr */ 1748 aclass(ctxt, &p->from); 1749 r = p->from.reg; 1750 if(r == NREG) 1751 r = o->param; 1752 o1 = olr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond); 1753 if(p->as != AMOVW) 1754 o1 |= 1<<22; 1755 break; 1756 1757 case 30: /* mov/movb/movbu R,L(R) */ 1758 o1 = omvl(ctxt, p, &p->to, REGTMP); 1759 if(!o1) 1760 break; 1761 r = p->to.reg; 1762 if(r == NREG) 1763 r = o->param; 1764 o2 = osrr(ctxt, p->from.reg, REGTMP,r, p->scond); 1765 if(p->as != AMOVW) 1766 o2 |= 1<<22; 1767 break; 1768 1769 case 31: /* mov/movbu L(R),R -> lr[b] */ 1770 o1 = omvl(ctxt, p, &p->from, REGTMP); 1771 if(!o1) 1772 break; 1773 r = p->from.reg; 1774 if(r == NREG) 1775 r = o->param; 1776 o2 = olrr(ctxt, REGTMP,r, p->to.reg, p->scond); 1777 if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB) 1778 o2 |= 1<<22; 1779 break; 1780 1781 case 34: /* mov $lacon,R */ 1782 o1 = omvl(ctxt, p, &p->from, REGTMP); 1783 if(!o1) 1784 break; 1785 1786 o2 = oprrr(ctxt, AADD, p->scond); 1787 o2 |= REGTMP; 1788 r = p->from.reg; 1789 if(r == NREG) 1790 r = o->param; 1791 o2 |= r << 16; 1792 if(p->to.type != D_NONE) 1793 o2 |= p->to.reg << 12; 1794 break; 1795 1796 case 35: /* mov PSR,R */ 1797 o1 = (2<<23) | (0xf<<16) | (0<<0); 1798 o1 |= (p->scond & C_SCOND) << 28; 1799 o1 |= (p->from.reg & 1) << 22; 1800 o1 |= p->to.reg << 12; 1801 break; 1802 1803 case 36: /* mov R,PSR */ 1804 o1 = (2<<23) | (0x29f<<12) | (0<<4); 1805 if(p->scond & C_FBIT) 1806 o1 ^= 0x010 << 12; 1807 o1 |= (p->scond & C_SCOND) << 28; 1808 o1 |= (p->to.reg & 1) << 22; 1809 o1 |= p->from.reg << 0; 1810 break; 1811 1812 case 37: /* mov $con,PSR */ 1813 aclass(ctxt, &p->from); 1814 o1 = (2<<23) | (0x29f<<12) | (0<<4); 1815 if(p->scond & C_FBIT) 1816 o1 ^= 0x010 << 12; 1817 o1 |= (p->scond & C_SCOND) << 28; 1818 o1 |= immrot(ctxt->instoffset); 1819 o1 |= (p->to.reg & 1) << 22; 1820 o1 |= p->from.reg << 0; 1821 break; 1822 1823 case 38: 1824 case 39: 1825 switch(o->type) { 1826 case 38: /* movm $con,oreg -> stm */ 1827 o1 = (0x4 << 25); 1828 o1 |= p->from.offset & 0xffff; 1829 o1 |= p->to.reg << 16; 1830 aclass(ctxt, &p->to); 1831 break; 1832 1833 case 39: /* movm oreg,$con -> ldm */ 1834 o1 = (0x4 << 25) | (1 << 20); 1835 o1 |= p->to.offset & 0xffff; 1836 o1 |= p->from.reg << 16; 1837 aclass(ctxt, &p->from); 1838 break; 1839 } 1840 if(ctxt->instoffset != 0) 1841 ctxt->diag("offset must be zero in MOVM; %P", p); 1842 o1 |= (p->scond & C_SCOND) << 28; 1843 if(p->scond & C_PBIT) 1844 o1 |= 1 << 24; 1845 if(p->scond & C_UBIT) 1846 o1 |= 1 << 23; 1847 if(p->scond & C_SBIT) 1848 o1 |= 1 << 22; 1849 if(p->scond & C_WBIT) 1850 o1 |= 1 << 21; 1851 break; 1852 1853 case 40: /* swp oreg,reg,reg */ 1854 aclass(ctxt, &p->from); 1855 if(ctxt->instoffset != 0) 1856 ctxt->diag("offset must be zero in SWP"); 1857 o1 = (0x2<<23) | (0x9<<4); 1858 if(p->as != ASWPW) 1859 o1 |= 1 << 22; 1860 o1 |= p->from.reg << 16; 1861 o1 |= p->reg << 0; 1862 o1 |= p->to.reg << 12; 1863 o1 |= (p->scond & C_SCOND) << 28; 1864 break; 1865 1866 case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ 1867 o1 = 0xe8fd8000; 1868 break; 1869 1870 case 50: /* floating point store */ 1871 v = regoff(ctxt, &p->to); 1872 r = p->to.reg; 1873 if(r == NREG) 1874 r = o->param; 1875 o1 = ofsr(ctxt, p->as, p->from.reg, v, r, p->scond, p); 1876 break; 1877 1878 case 51: /* floating point load */ 1879 v = regoff(ctxt, &p->from); 1880 r = p->from.reg; 1881 if(r == NREG) 1882 r = o->param; 1883 o1 = ofsr(ctxt, p->as, p->to.reg, v, r, p->scond, p) | (1<<20); 1884 break; 1885 1886 case 52: /* floating point store, int32 offset UGLY */ 1887 o1 = omvl(ctxt, p, &p->to, REGTMP); 1888 if(!o1) 1889 break; 1890 r = p->to.reg; 1891 if(r == NREG) 1892 r = o->param; 1893 o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; 1894 o3 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p); 1895 break; 1896 1897 case 53: /* floating point load, int32 offset UGLY */ 1898 o1 = omvl(ctxt, p, &p->from, REGTMP); 1899 if(!o1) 1900 break; 1901 r = p->from.reg; 1902 if(r == NREG) 1903 r = o->param; 1904 o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; 1905 o3 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); 1906 break; 1907 1908 case 54: /* floating point arith */ 1909 o1 = oprrr(ctxt, p->as, p->scond); 1910 rf = p->from.reg; 1911 rt = p->to.reg; 1912 r = p->reg; 1913 if(r == NREG) { 1914 r = rt; 1915 if(p->as == AMOVF || p->as == AMOVD || p->as == AMOVFD || p->as == AMOVDF || 1916 p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD) 1917 r = 0; 1918 } 1919 o1 |= rf | (r<<16) | (rt<<12); 1920 break; 1921 1922 case 56: /* move to FP[CS]R */ 1923 o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); 1924 o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12); 1925 break; 1926 1927 case 57: /* move from FP[CS]R */ 1928 o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); 1929 o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20); 1930 break; 1931 case 58: /* movbu R,R */ 1932 o1 = oprrr(ctxt, AAND, p->scond); 1933 o1 |= immrot(0xff); 1934 rt = p->to.reg; 1935 r = p->from.reg; 1936 if(p->to.type == D_NONE) 1937 rt = 0; 1938 if(r == NREG) 1939 r = rt; 1940 o1 |= (r<<16) | (rt<<12); 1941 break; 1942 1943 case 59: /* movw/bu R<<I(R),R -> ldr indexed */ 1944 if(p->from.reg == NREG) { 1945 if(p->as != AMOVW) 1946 ctxt->diag("byte MOV from shifter operand"); 1947 o1 = mov(ctxt, p); 1948 break; 1949 } 1950 if(p->from.offset&(1<<4)) 1951 ctxt->diag("bad shift in LDR"); 1952 o1 = olrr(ctxt, p->from.offset, p->from.reg, p->to.reg, p->scond); 1953 if(p->as == AMOVBU) 1954 o1 |= 1<<22; 1955 break; 1956 1957 case 60: /* movb R(R),R -> ldrsb indexed */ 1958 if(p->from.reg == NREG) { 1959 ctxt->diag("byte MOV from shifter operand"); 1960 o1 = mov(ctxt, p); 1961 break; 1962 } 1963 if(p->from.offset&(~0xf)) 1964 ctxt->diag("bad shift in LDRSB"); 1965 o1 = olhrr(ctxt, p->from.offset, p->from.reg, p->to.reg, p->scond); 1966 o1 ^= (1<<5)|(1<<6); 1967 break; 1968 1969 case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ 1970 if(p->to.reg == NREG) 1971 ctxt->diag("MOV to shifter operand"); 1972 o1 = osrr(ctxt, p->from.reg, p->to.offset, p->to.reg, p->scond); 1973 if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) 1974 o1 |= 1<<22; 1975 break; 1976 1977 case 62: /* case R -> movw R<<2(PC),PC */ 1978 if(o->flag & LPCREL) { 1979 o1 = oprrr(ctxt, AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12; 1980 o2 = olrr(ctxt, REGTMP, REGPC, REGTMP, p->scond); 1981 o2 |= 2<<7; 1982 o3 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12; 1983 } else { 1984 o1 = olrr(ctxt, p->from.reg, REGPC, REGPC, p->scond); 1985 o1 |= 2<<7; 1986 } 1987 break; 1988 1989 case 63: /* bcase */ 1990 if(p->pcond != nil) { 1991 rel = addrel(ctxt->cursym); 1992 rel->off = ctxt->pc; 1993 rel->siz = 4; 1994 if(p->to.sym != nil && p->to.sym->type != 0) { 1995 rel->sym = p->to.sym; 1996 rel->add = p->to.offset; 1997 } else { 1998 rel->sym = ctxt->cursym; 1999 rel->add = p->pcond->pc; 2000 } 2001 if(o->flag & LPCREL) { 2002 rel->type = R_PCREL; 2003 rel->add += ctxt->pc - p->pcrel->pc - 16 + rel->siz; 2004 } else 2005 rel->type = R_ADDR; 2006 o1 = 0; 2007 } 2008 break; 2009 2010 /* reloc ops */ 2011 case 64: /* mov/movb/movbu R,addr */ 2012 o1 = omvl(ctxt, p, &p->to, REGTMP); 2013 if(!o1) 2014 break; 2015 o2 = osr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond); 2016 if(o->flag & LPCREL) { 2017 o3 = o2; 2018 o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 2019 } 2020 break; 2021 2022 case 65: /* mov/movbu addr,R */ 2023 o1 = omvl(ctxt, p, &p->from, REGTMP); 2024 if(!o1) 2025 break; 2026 o2 = olr(ctxt, 0, REGTMP, p->to.reg, p->scond); 2027 if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB) 2028 o2 |= 1<<22; 2029 if(o->flag & LPCREL) { 2030 o3 = o2; 2031 o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 2032 } 2033 break; 2034 2035 case 68: /* floating point store -> ADDR */ 2036 o1 = omvl(ctxt, p, &p->to, REGTMP); 2037 if(!o1) 2038 break; 2039 o2 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p); 2040 if(o->flag & LPCREL) { 2041 o3 = o2; 2042 o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 2043 } 2044 break; 2045 2046 case 69: /* floating point load <- ADDR */ 2047 o1 = omvl(ctxt, p, &p->from, REGTMP); 2048 if(!o1) 2049 break; 2050 o2 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); 2051 if(o->flag & LPCREL) { 2052 o3 = o2; 2053 o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 2054 } 2055 break; 2056 2057 /* ArmV4 ops: */ 2058 case 70: /* movh/movhu R,O(R) -> strh */ 2059 aclass(ctxt, &p->to); 2060 r = p->to.reg; 2061 if(r == NREG) 2062 r = o->param; 2063 o1 = oshr(ctxt, p->from.reg, ctxt->instoffset, r, p->scond); 2064 break; 2065 case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ 2066 aclass(ctxt, &p->from); 2067 r = p->from.reg; 2068 if(r == NREG) 2069 r = o->param; 2070 o1 = olhr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond); 2071 if(p->as == AMOVB || p->as == AMOVBS) 2072 o1 ^= (1<<5)|(1<<6); 2073 else if(p->as == AMOVH || p->as == AMOVHS) 2074 o1 ^= (1<<6); 2075 break; 2076 case 72: /* movh/movhu R,L(R) -> strh */ 2077 o1 = omvl(ctxt, p, &p->to, REGTMP); 2078 if(!o1) 2079 break; 2080 r = p->to.reg; 2081 if(r == NREG) 2082 r = o->param; 2083 o2 = oshrr(ctxt, p->from.reg, REGTMP,r, p->scond); 2084 break; 2085 case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ 2086 o1 = omvl(ctxt, p, &p->from, REGTMP); 2087 if(!o1) 2088 break; 2089 r = p->from.reg; 2090 if(r == NREG) 2091 r = o->param; 2092 o2 = olhrr(ctxt, REGTMP, r, p->to.reg, p->scond); 2093 if(p->as == AMOVB || p->as == AMOVBS) 2094 o2 ^= (1<<5)|(1<<6); 2095 else if(p->as == AMOVH || p->as == AMOVHS) 2096 o2 ^= (1<<6); 2097 break; 2098 case 74: /* bx $I */ 2099 ctxt->diag("ABX $I"); 2100 break; 2101 case 75: /* bx O(R) */ 2102 aclass(ctxt, &p->to); 2103 if(ctxt->instoffset != 0) 2104 ctxt->diag("non-zero offset in ABX"); 2105 /* 2106 o1 = oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR 2107 o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R 2108 */ 2109 // p->to.reg may be REGLINK 2110 o1 = oprrr(ctxt, AADD, p->scond); 2111 o1 |= immrot(ctxt->instoffset); 2112 o1 |= p->to.reg << 16; 2113 o1 |= REGTMP << 12; 2114 o2 = oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR 2115 o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp 2116 break; 2117 case 76: /* bx O(R) when returning from fn*/ 2118 ctxt->diag("ABXRET"); 2119 break; 2120 case 77: /* ldrex oreg,reg */ 2121 aclass(ctxt, &p->from); 2122 if(ctxt->instoffset != 0) 2123 ctxt->diag("offset must be zero in LDREX"); 2124 o1 = (0x19<<20) | (0xf9f); 2125 o1 |= p->from.reg << 16; 2126 o1 |= p->to.reg << 12; 2127 o1 |= (p->scond & C_SCOND) << 28; 2128 break; 2129 case 78: /* strex reg,oreg,reg */ 2130 aclass(ctxt, &p->from); 2131 if(ctxt->instoffset != 0) 2132 ctxt->diag("offset must be zero in STREX"); 2133 o1 = (0x18<<20) | (0xf90); 2134 o1 |= p->from.reg << 16; 2135 o1 |= p->reg << 0; 2136 o1 |= p->to.reg << 12; 2137 o1 |= (p->scond & C_SCOND) << 28; 2138 break; 2139 case 80: /* fmov zfcon,freg */ 2140 if(p->as == AMOVD) { 2141 o1 = 0xeeb00b00; // VMOV imm 64 2142 o2 = oprrr(ctxt, ASUBD, p->scond); 2143 } else { 2144 o1 = 0x0eb00a00; // VMOV imm 32 2145 o2 = oprrr(ctxt, ASUBF, p->scond); 2146 } 2147 v = 0x70; // 1.0 2148 r = p->to.reg; 2149 2150 // movf $1.0, r 2151 o1 |= (p->scond & C_SCOND) << 28; 2152 o1 |= r << 12; 2153 o1 |= (v&0xf) << 0; 2154 o1 |= (v&0xf0) << 12; 2155 2156 // subf r,r,r 2157 o2 |= r | (r<<16) | (r<<12); 2158 break; 2159 case 81: /* fmov sfcon,freg */ 2160 o1 = 0x0eb00a00; // VMOV imm 32 2161 if(p->as == AMOVD) 2162 o1 = 0xeeb00b00; // VMOV imm 64 2163 o1 |= (p->scond & C_SCOND) << 28; 2164 o1 |= p->to.reg << 12; 2165 v = chipfloat5(ctxt, p->from.u.dval); 2166 o1 |= (v&0xf) << 0; 2167 o1 |= (v&0xf0) << 12; 2168 break; 2169 case 82: /* fcmp freg,freg, */ 2170 o1 = oprrr(ctxt, p->as, p->scond); 2171 o1 |= (p->reg<<12) | (p->from.reg<<0); 2172 o2 = 0x0ef1fa10; // VMRS R15 2173 o2 |= (p->scond & C_SCOND) << 28; 2174 break; 2175 case 83: /* fcmp freg,, */ 2176 o1 = oprrr(ctxt, p->as, p->scond); 2177 o1 |= (p->from.reg<<12) | (1<<16); 2178 o2 = 0x0ef1fa10; // VMRS R15 2179 o2 |= (p->scond & C_SCOND) << 28; 2180 break; 2181 case 84: /* movfw freg,freg - truncate float-to-fix */ 2182 o1 = oprrr(ctxt, p->as, p->scond); 2183 o1 |= (p->from.reg<<0); 2184 o1 |= (p->to.reg<<12); 2185 break; 2186 case 85: /* movwf freg,freg - fix-to-float */ 2187 o1 = oprrr(ctxt, p->as, p->scond); 2188 o1 |= (p->from.reg<<0); 2189 o1 |= (p->to.reg<<12); 2190 break; 2191 case 86: /* movfw freg,reg - truncate float-to-fix */ 2192 // macro for movfw freg,FTMP; movw FTMP,reg 2193 o1 = oprrr(ctxt, p->as, p->scond); 2194 o1 |= (p->from.reg<<0); 2195 o1 |= (FREGTMP<<12); 2196 o2 = oprrr(ctxt, AMOVFW+AEND, p->scond); 2197 o2 |= (FREGTMP<<16); 2198 o2 |= (p->to.reg<<12); 2199 break; 2200 case 87: /* movwf reg,freg - fix-to-float */ 2201 // macro for movw reg,FTMP; movwf FTMP,freg 2202 o1 = oprrr(ctxt, AMOVWF+AEND, p->scond); 2203 o1 |= (p->from.reg<<12); 2204 o1 |= (FREGTMP<<16); 2205 o2 = oprrr(ctxt, p->as, p->scond); 2206 o2 |= (FREGTMP<<0); 2207 o2 |= (p->to.reg<<12); 2208 break; 2209 case 88: /* movw reg,freg */ 2210 o1 = oprrr(ctxt, AMOVWF+AEND, p->scond); 2211 o1 |= (p->from.reg<<12); 2212 o1 |= (p->to.reg<<16); 2213 break; 2214 case 89: /* movw freg,reg */ 2215 o1 = oprrr(ctxt, AMOVFW+AEND, p->scond); 2216 o1 |= (p->from.reg<<16); 2217 o1 |= (p->to.reg<<12); 2218 break; 2219 case 90: /* tst reg */ 2220 o1 = oprrr(ctxt, ACMP+AEND, p->scond); 2221 o1 |= p->from.reg<<16; 2222 break; 2223 case 91: /* ldrexd oreg,reg */ 2224 aclass(ctxt, &p->from); 2225 if(ctxt->instoffset != 0) 2226 ctxt->diag("offset must be zero in LDREX"); 2227 o1 = (0x1b<<20) | (0xf9f); 2228 o1 |= p->from.reg << 16; 2229 o1 |= p->to.reg << 12; 2230 o1 |= (p->scond & C_SCOND) << 28; 2231 break; 2232 case 92: /* strexd reg,oreg,reg */ 2233 aclass(ctxt, &p->from); 2234 if(ctxt->instoffset != 0) 2235 ctxt->diag("offset must be zero in STREX"); 2236 o1 = (0x1a<<20) | (0xf90); 2237 o1 |= p->from.reg << 16; 2238 o1 |= p->reg << 0; 2239 o1 |= p->to.reg << 12; 2240 o1 |= (p->scond & C_SCOND) << 28; 2241 break; 2242 case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ 2243 o1 = omvl(ctxt, p, &p->from, REGTMP); 2244 if(!o1) 2245 break; 2246 o2 = olhr(ctxt, 0, REGTMP, p->to.reg, p->scond); 2247 if(p->as == AMOVB || p->as == AMOVBS) 2248 o2 ^= (1<<5)|(1<<6); 2249 else if(p->as == AMOVH || p->as == AMOVHS) 2250 o2 ^= (1<<6); 2251 if(o->flag & LPCREL) { 2252 o3 = o2; 2253 o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 2254 } 2255 break; 2256 case 94: /* movh/movhu R,addr -> strh */ 2257 o1 = omvl(ctxt, p, &p->to, REGTMP); 2258 if(!o1) 2259 break; 2260 o2 = oshr(ctxt, p->from.reg, 0, REGTMP, p->scond); 2261 if(o->flag & LPCREL) { 2262 o3 = o2; 2263 o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; 2264 } 2265 break; 2266 case 95: /* PLD off(reg) */ 2267 o1 = 0xf5d0f000; 2268 o1 |= p->from.reg << 16; 2269 if(p->from.offset < 0) { 2270 o1 &= ~(1 << 23); 2271 o1 |= (-p->from.offset) & 0xfff; 2272 } else 2273 o1 |= p->from.offset & 0xfff; 2274 break; 2275 case 96: /* UNDEF */ 2276 // This is supposed to be something that stops execution. 2277 // It's not supposed to be reached, ever, but if it is, we'd 2278 // like to be able to tell how we got there. Assemble as 2279 // 0xf7fabcfd which is guaranteed to raise undefined instruction 2280 // exception. 2281 o1 = 0xf7fabcfd; 2282 break; 2283 case 97: /* CLZ Rm, Rd */ 2284 o1 = oprrr(ctxt, p->as, p->scond); 2285 o1 |= p->to.reg << 12; 2286 o1 |= p->from.reg; 2287 break; 2288 case 98: /* MULW{T,B} Rs, Rm, Rd */ 2289 o1 = oprrr(ctxt, p->as, p->scond); 2290 o1 |= p->to.reg << 16; 2291 o1 |= p->from.reg << 8; 2292 o1 |= p->reg; 2293 break; 2294 case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ 2295 o1 = oprrr(ctxt, p->as, p->scond); 2296 o1 |= p->to.reg << 12; 2297 o1 |= p->from.reg << 8; 2298 o1 |= p->reg; 2299 o1 |= p->to.offset << 16; 2300 break; 2301 case 100: 2302 // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle; 2303 // DATABUNDLEEND: zero width alignment marker 2304 if(p->as == ADATABUNDLE) 2305 o1 = 0xe125be70; 2306 break; 2307 } 2308 2309 out[0] = o1; 2310 out[1] = o2; 2311 out[2] = o3; 2312 out[3] = o4; 2313 out[4] = o5; 2314 out[5] = o6; 2315 return; 2316 } 2317 2318 static int32 2319 mov(Link *ctxt, Prog *p) 2320 { 2321 int32 o1; 2322 int rt, r; 2323 2324 aclass(ctxt, &p->from); 2325 o1 = oprrr(ctxt, p->as, p->scond); 2326 o1 |= p->from.offset; 2327 rt = p->to.reg; 2328 r = p->reg; 2329 if(p->to.type == D_NONE) 2330 rt = 0; 2331 if(p->as == AMOVW || p->as == AMVN) 2332 r = 0; 2333 else if(r == NREG) 2334 r = rt; 2335 o1 |= (r<<16) | (rt<<12); 2336 return o1; 2337 } 2338 2339 static int32 2340 oprrr(Link *ctxt, int a, int sc) 2341 { 2342 int32 o; 2343 2344 o = (sc & C_SCOND) << 28; 2345 if(sc & C_SBIT) 2346 o |= 1 << 20; 2347 if(sc & (C_PBIT|C_WBIT)) 2348 ctxt->diag(".nil/.W on dp instruction"); 2349 switch(a) { 2350 case AMULU: 2351 case AMUL: return o | (0x0<<21) | (0x9<<4); 2352 case AMULA: return o | (0x1<<21) | (0x9<<4); 2353 case AMULLU: return o | (0x4<<21) | (0x9<<4); 2354 case AMULL: return o | (0x6<<21) | (0x9<<4); 2355 case AMULALU: return o | (0x5<<21) | (0x9<<4); 2356 case AMULAL: return o | (0x7<<21) | (0x9<<4); 2357 case AAND: return o | (0x0<<21); 2358 case AEOR: return o | (0x1<<21); 2359 case ASUB: return o | (0x2<<21); 2360 case ARSB: return o | (0x3<<21); 2361 case AADD: return o | (0x4<<21); 2362 case AADC: return o | (0x5<<21); 2363 case ASBC: return o | (0x6<<21); 2364 case ARSC: return o | (0x7<<21); 2365 case ATST: return o | (0x8<<21) | (1<<20); 2366 case ATEQ: return o | (0x9<<21) | (1<<20); 2367 case ACMP: return o | (0xa<<21) | (1<<20); 2368 case ACMN: return o | (0xb<<21) | (1<<20); 2369 case AORR: return o | (0xc<<21); 2370 case AMOVB: 2371 case AMOVH: 2372 case AMOVW: return o | (0xd<<21); 2373 case ABIC: return o | (0xe<<21); 2374 case AMVN: return o | (0xf<<21); 2375 case ASLL: return o | (0xd<<21) | (0<<5); 2376 case ASRL: return o | (0xd<<21) | (1<<5); 2377 case ASRA: return o | (0xd<<21) | (2<<5); 2378 case ASWI: return o | (0xf<<24); 2379 2380 case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4); 2381 case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4); 2382 case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4); 2383 case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4); 2384 case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4); 2385 case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4); 2386 case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4); 2387 case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4); 2388 case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4); 2389 case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4); 2390 case AABSD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4); 2391 case AABSF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<4); 2392 case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4); 2393 case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4); 2394 2395 case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4); 2396 case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4); 2397 2398 case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | 2399 (1<<8); // dtof 2400 case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | 2401 (0<<8); // dtof 2402 2403 case AMOVWF: 2404 if((sc & C_UBIT) == 0) 2405 o |= 1<<7; /* signed */ 2406 return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | 2407 (0<<18) | (0<<8); // toint, double 2408 case AMOVWD: 2409 if((sc & C_UBIT) == 0) 2410 o |= 1<<7; /* signed */ 2411 return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | 2412 (0<<18) | (1<<8); // toint, double 2413 2414 case AMOVFW: 2415 if((sc & C_UBIT) == 0) 2416 o |= 1<<16; /* signed */ 2417 return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | 2418 (1<<18) | (0<<8) | (1<<7); // toint, double, trunc 2419 case AMOVDW: 2420 if((sc & C_UBIT) == 0) 2421 o |= 1<<16; /* signed */ 2422 return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | 2423 (1<<18) | (1<<8) | (1<<7); // toint, double, trunc 2424 2425 case AMOVWF+AEND: // copy WtoF 2426 return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4); 2427 case AMOVFW+AEND: // copy FtoW 2428 return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4); 2429 case ACMP+AEND: // cmp imm 2430 return o | (0x3<<24) | (0x5<<20); 2431 2432 case ACLZ: 2433 // CLZ doesn't support .nil 2434 return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4); 2435 2436 case AMULWT: 2437 return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4); 2438 case AMULWB: 2439 return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4); 2440 case AMULAWT: 2441 return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4); 2442 case AMULAWB: 2443 return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4); 2444 2445 case ABL: // BLX REG 2446 return (o & (0xf<<28)) | (0x12fff3 << 4); 2447 } 2448 ctxt->diag("bad rrr %d", a); 2449 prasm(ctxt->curp); 2450 return 0; 2451 } 2452 2453 static int32 2454 opbra(Link *ctxt, int a, int sc) 2455 { 2456 2457 if(sc & (C_SBIT|C_PBIT|C_WBIT)) 2458 ctxt->diag(".nil/.nil/.W on bra instruction"); 2459 sc &= C_SCOND; 2460 if(a == ABL || a == ADUFFZERO || a == ADUFFCOPY) 2461 return (sc<<28)|(0x5<<25)|(0x1<<24); 2462 if(sc != 0xe) 2463 ctxt->diag(".COND on bcond instruction"); 2464 switch(a) { 2465 case ABEQ: return (0x0<<28)|(0x5<<25); 2466 case ABNE: return (0x1<<28)|(0x5<<25); 2467 case ABCS: return (0x2<<28)|(0x5<<25); 2468 case ABHS: return (0x2<<28)|(0x5<<25); 2469 case ABCC: return (0x3<<28)|(0x5<<25); 2470 case ABLO: return (0x3<<28)|(0x5<<25); 2471 case ABMI: return (0x4<<28)|(0x5<<25); 2472 case ABPL: return (0x5<<28)|(0x5<<25); 2473 case ABVS: return (0x6<<28)|(0x5<<25); 2474 case ABVC: return (0x7<<28)|(0x5<<25); 2475 case ABHI: return (0x8<<28)|(0x5<<25); 2476 case ABLS: return (0x9<<28)|(0x5<<25); 2477 case ABGE: return (0xa<<28)|(0x5<<25); 2478 case ABLT: return (0xb<<28)|(0x5<<25); 2479 case ABGT: return (0xc<<28)|(0x5<<25); 2480 case ABLE: return (0xd<<28)|(0x5<<25); 2481 case AB: return (0xe<<28)|(0x5<<25); 2482 } 2483 ctxt->diag("bad bra %A", a); 2484 prasm(ctxt->curp); 2485 return 0; 2486 } 2487 2488 static int32 2489 olr(Link *ctxt, int32 v, int b, int r, int sc) 2490 { 2491 int32 o; 2492 2493 if(sc & C_SBIT) 2494 ctxt->diag(".nil on LDR/STR instruction"); 2495 o = (sc & C_SCOND) << 28; 2496 if(!(sc & C_PBIT)) 2497 o |= 1 << 24; 2498 if(!(sc & C_UBIT)) 2499 o |= 1 << 23; 2500 if(sc & C_WBIT) 2501 o |= 1 << 21; 2502 o |= (1<<26) | (1<<20); 2503 if(v < 0) { 2504 if(sc & C_UBIT) 2505 ctxt->diag(".U on neg offset"); 2506 v = -v; 2507 o ^= 1 << 23; 2508 } 2509 if(v >= (1<<12) || v < 0) 2510 ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp); 2511 o |= v; 2512 o |= b << 16; 2513 o |= r << 12; 2514 return o; 2515 } 2516 2517 static int32 2518 olhr(Link *ctxt, int32 v, int b, int r, int sc) 2519 { 2520 int32 o; 2521 2522 if(sc & C_SBIT) 2523 ctxt->diag(".nil on LDRH/STRH instruction"); 2524 o = (sc & C_SCOND) << 28; 2525 if(!(sc & C_PBIT)) 2526 o |= 1 << 24; 2527 if(sc & C_WBIT) 2528 o |= 1 << 21; 2529 o |= (1<<23) | (1<<20)|(0xb<<4); 2530 if(v < 0) { 2531 v = -v; 2532 o ^= 1 << 23; 2533 } 2534 if(v >= (1<<8) || v < 0) 2535 ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp); 2536 o |= (v&0xf)|((v>>4)<<8)|(1<<22); 2537 o |= b << 16; 2538 o |= r << 12; 2539 return o; 2540 } 2541 2542 static int32 2543 osr(Link *ctxt, int a, int r, int32 v, int b, int sc) 2544 { 2545 int32 o; 2546 2547 o = olr(ctxt, v, b, r, sc) ^ (1<<20); 2548 if(a != AMOVW) 2549 o |= 1<<22; 2550 return o; 2551 } 2552 2553 static int32 2554 oshr(Link *ctxt, int r, int32 v, int b, int sc) 2555 { 2556 int32 o; 2557 2558 o = olhr(ctxt, v, b, r, sc) ^ (1<<20); 2559 return o; 2560 } 2561 2562 2563 static int32 2564 osrr(Link *ctxt, int r, int i, int b, int sc) 2565 { 2566 2567 return olr(ctxt, i, b, r, sc) ^ ((1<<25) | (1<<20)); 2568 } 2569 2570 static int32 2571 oshrr(Link *ctxt, int r, int i, int b, int sc) 2572 { 2573 return olhr(ctxt, i, b, r, sc) ^ ((1<<22) | (1<<20)); 2574 } 2575 2576 static int32 2577 olrr(Link *ctxt, int i, int b, int r, int sc) 2578 { 2579 2580 return olr(ctxt, i, b, r, sc) ^ (1<<25); 2581 } 2582 2583 static int32 2584 olhrr(Link *ctxt, int i, int b, int r, int sc) 2585 { 2586 return olhr(ctxt, i, b, r, sc) ^ (1<<22); 2587 } 2588 2589 static int32 2590 ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p) 2591 { 2592 int32 o; 2593 2594 if(sc & C_SBIT) 2595 ctxt->diag(".nil on FLDR/FSTR instruction"); 2596 o = (sc & C_SCOND) << 28; 2597 if(!(sc & C_PBIT)) 2598 o |= 1 << 24; 2599 if(sc & C_WBIT) 2600 o |= 1 << 21; 2601 o |= (6<<25) | (1<<24) | (1<<23) | (10<<8); 2602 if(v < 0) { 2603 v = -v; 2604 o ^= 1 << 23; 2605 } 2606 if(v & 3) 2607 ctxt->diag("odd offset for floating point op: %d\n%P", v, p); 2608 else 2609 if(v >= (1<<10) || v < 0) 2610 ctxt->diag("literal span too large: %d\n%P", v, p); 2611 o |= (v>>2) & 0xFF; 2612 o |= b << 16; 2613 o |= r << 12; 2614 2615 switch(a) { 2616 default: 2617 ctxt->diag("bad fst %A", a); 2618 case AMOVD: 2619 o |= 1 << 8; 2620 case AMOVF: 2621 break; 2622 } 2623 return o; 2624 } 2625 2626 static int32 2627 omvl(Link *ctxt, Prog *p, Addr *a, int dr) 2628 { 2629 int32 v, o1; 2630 if(!p->pcond) { 2631 aclass(ctxt, a); 2632 v = immrot(~ctxt->instoffset); 2633 if(v == 0) { 2634 ctxt->diag("missing literal"); 2635 prasm(p); 2636 return 0; 2637 } 2638 o1 = oprrr(ctxt, AMVN, p->scond&C_SCOND); 2639 o1 |= v; 2640 o1 |= dr << 12; 2641 } else { 2642 v = p->pcond->pc - p->pc - 8; 2643 o1 = olr(ctxt, v, REGPC, dr, p->scond&C_SCOND); 2644 } 2645 return o1; 2646 } 2647 2648 int 2649 chipzero5(Link *ctxt, float64 e) 2650 { 2651 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 2652 if(ctxt->goarm < 7 || e != 0) 2653 return -1; 2654 return 0; 2655 } 2656 2657 int 2658 chipfloat5(Link *ctxt, float64 e) 2659 { 2660 int n; 2661 ulong h1; 2662 int32 l, h; 2663 uint64 ei; 2664 2665 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 2666 if(ctxt->goarm < 7) 2667 goto no; 2668 2669 memmove(&ei, &e, 8); 2670 l = (int32)ei; 2671 h = (int32)(ei>>32); 2672 2673 if(l != 0 || (h&0xffff) != 0) 2674 goto no; 2675 h1 = h & 0x7fc00000; 2676 if(h1 != 0x40000000 && h1 != 0x3fc00000) 2677 goto no; 2678 n = 0; 2679 2680 // sign bit (a) 2681 if(h & 0x80000000) 2682 n |= 1<<7; 2683 2684 // exp sign bit (b) 2685 if(h1 == 0x3fc00000) 2686 n |= 1<<6; 2687 2688 // rest of exp and mantissa (cd-efgh) 2689 n |= (h >> 16) & 0x3f; 2690 2691 //print("match %.8lux %.8lux %d\n", l, h, n); 2692 return n; 2693 2694 no: 2695 return -1; 2696 }