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