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