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