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