github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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 if a.Reg == REGSP { 1171 // unset base register for better printing, since 1172 // a.Offset is still relative to pseudo-SP. 1173 a.Reg = obj.REG_NONE 1174 } 1175 c.instoffset = c.autosize + a.Offset 1176 if t := immaddr(int32(c.instoffset)); t != 0 { 1177 if immhalf(int32(c.instoffset)) { 1178 if immfloat(t) { 1179 return C_HFAUTO 1180 } 1181 return C_HAUTO 1182 } 1183 1184 if immfloat(t) { 1185 return C_FAUTO 1186 } 1187 return C_SAUTO 1188 } 1189 1190 return C_LAUTO 1191 1192 case obj.NAME_PARAM: 1193 if a.Reg == REGSP { 1194 // unset base register for better printing, since 1195 // a.Offset is still relative to pseudo-FP. 1196 a.Reg = obj.REG_NONE 1197 } 1198 c.instoffset = c.autosize + a.Offset + 4 1199 if t := immaddr(int32(c.instoffset)); t != 0 { 1200 if immhalf(int32(c.instoffset)) { 1201 if immfloat(t) { 1202 return C_HFAUTO 1203 } 1204 return C_HAUTO 1205 } 1206 1207 if immfloat(t) { 1208 return C_FAUTO 1209 } 1210 return C_SAUTO 1211 } 1212 1213 return C_LAUTO 1214 1215 case obj.NAME_NONE: 1216 c.instoffset = a.Offset 1217 if t := immaddr(int32(c.instoffset)); t != 0 { 1218 if immhalf(int32(c.instoffset)) { /* n.b. that it will also satisfy immrot */ 1219 if immfloat(t) { 1220 return C_HFOREG 1221 } 1222 return C_HOREG 1223 } 1224 1225 if immfloat(t) { 1226 return C_FOREG /* n.b. that it will also satisfy immrot */ 1227 } 1228 if immrot(uint32(c.instoffset)) != 0 { 1229 return C_SROREG 1230 } 1231 if immhalf(int32(c.instoffset)) { 1232 return C_HOREG 1233 } 1234 return C_SOREG 1235 } 1236 1237 if immrot(uint32(c.instoffset)) != 0 { 1238 return C_ROREG 1239 } 1240 return C_LOREG 1241 } 1242 1243 return C_GOK 1244 1245 case obj.TYPE_FCONST: 1246 if c.chipzero5(a.Val.(float64)) >= 0 { 1247 return C_ZFCON 1248 } 1249 if c.chipfloat5(a.Val.(float64)) >= 0 { 1250 return C_SFCON 1251 } 1252 return C_LFCON 1253 1254 case obj.TYPE_TEXTSIZE: 1255 return C_TEXTSIZE 1256 1257 case obj.TYPE_CONST, 1258 obj.TYPE_ADDR: 1259 switch a.Name { 1260 case obj.NAME_NONE: 1261 c.instoffset = a.Offset 1262 if a.Reg != 0 { 1263 return c.aconsize() 1264 } 1265 1266 if immrot(uint32(c.instoffset)) != 0 { 1267 return C_RCON 1268 } 1269 if immrot(^uint32(c.instoffset)) != 0 { 1270 return C_NCON 1271 } 1272 if uint32(c.instoffset) <= 0xffff && objabi.GOARM == 7 { 1273 return C_SCON 1274 } 1275 if c.ctxt.Headtype != objabi.Hnacl { 1276 // Don't split instructions on NaCl. The validator is not 1277 // happy with it. See Issue 20595. 1278 if x, y := immrot2a(uint32(c.instoffset)); x != 0 && y != 0 { 1279 return C_RCON2A 1280 } 1281 if y, x := immrot2s(uint32(c.instoffset)); x != 0 && y != 0 { 1282 return C_RCON2S 1283 } 1284 } 1285 return C_LCON 1286 1287 case obj.NAME_EXTERN, 1288 obj.NAME_GOTREF, 1289 obj.NAME_STATIC: 1290 s := a.Sym 1291 if s == nil { 1292 break 1293 } 1294 c.instoffset = 0 // s.b. unused but just in case 1295 return C_LCONADDR 1296 1297 case obj.NAME_AUTO: 1298 if a.Reg == REGSP { 1299 // unset base register for better printing, since 1300 // a.Offset is still relative to pseudo-SP. 1301 a.Reg = obj.REG_NONE 1302 } 1303 c.instoffset = c.autosize + a.Offset 1304 return c.aconsize() 1305 1306 case obj.NAME_PARAM: 1307 if a.Reg == REGSP { 1308 // unset base register for better printing, since 1309 // a.Offset is still relative to pseudo-FP. 1310 a.Reg = obj.REG_NONE 1311 } 1312 c.instoffset = c.autosize + a.Offset + 4 1313 return c.aconsize() 1314 } 1315 1316 return C_GOK 1317 1318 case obj.TYPE_BRANCH: 1319 return C_SBRA 1320 } 1321 1322 return C_GOK 1323 } 1324 1325 func (c *ctxt5) aconsize() int { 1326 if immrot(uint32(c.instoffset)) != 0 { 1327 return C_RACON 1328 } 1329 if immrot(uint32(-c.instoffset)) != 0 { 1330 return C_RACON 1331 } 1332 return C_LACON 1333 } 1334 1335 func (c *ctxt5) oplook(p *obj.Prog) *Optab { 1336 a1 := int(p.Optab) 1337 if a1 != 0 { 1338 return &optab[a1-1] 1339 } 1340 a1 = int(p.From.Class) 1341 if a1 == 0 { 1342 a1 = c.aclass(&p.From) + 1 1343 p.From.Class = int8(a1) 1344 } 1345 1346 a1-- 1347 a3 := int(p.To.Class) 1348 if a3 == 0 { 1349 a3 = c.aclass(&p.To) + 1 1350 p.To.Class = int8(a3) 1351 } 1352 1353 a3-- 1354 a2 := C_NONE 1355 if p.Reg != 0 { 1356 switch { 1357 case REG_F0 <= p.Reg && p.Reg <= REG_F15: 1358 a2 = C_FREG 1359 case REG_R0 <= p.Reg && p.Reg <= REG_R15: 1360 a2 = C_REG 1361 default: 1362 c.ctxt.Diag("invalid register in %v", p) 1363 } 1364 } 1365 1366 // check illegal base register 1367 switch a1 { 1368 case C_SHIFT: 1369 if p.From.Reg == 0 { // no base register 1370 break 1371 } 1372 fallthrough 1373 case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG: 1374 if p.From.Reg < REG_R0 || REG_R15 < p.From.Reg { 1375 c.ctxt.Diag("illegal base register: %v", p) 1376 } 1377 default: 1378 } 1379 switch a3 { 1380 case C_SOREG, C_LOREG, C_HOREG, C_FOREG, C_ROREG, C_HFOREG, C_SROREG, C_SHIFT: 1381 if p.To.Reg < REG_R0 || REG_R15 < p.To.Reg { 1382 c.ctxt.Diag("illegal base register: %v", p) 1383 } 1384 default: 1385 } 1386 1387 // If current instruction has a .S suffix (flags update), 1388 // we must use the constant pool instead of splitting it. 1389 if (a1 == C_RCON2A || a1 == C_RCON2S) && p.Scond&C_SBIT != 0 { 1390 a1 = C_LCON 1391 } 1392 if (a3 == C_RCON2A || a3 == C_RCON2S) && p.Scond&C_SBIT != 0 { 1393 a3 = C_LCON 1394 } 1395 1396 if false { /*debug['O']*/ 1397 fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3)) 1398 fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type) 1399 } 1400 1401 ops := oprange[p.As&obj.AMask] 1402 c1 := &xcmp[a1] 1403 c3 := &xcmp[a3] 1404 for i := range ops { 1405 op := &ops[i] 1406 if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] { 1407 p.Optab = uint16(cap(optab) - cap(ops) + i + 1) 1408 return op 1409 } 1410 } 1411 1412 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) 1413 if ops == nil { 1414 ops = optab 1415 } 1416 return &ops[0] 1417 } 1418 1419 func cmp(a int, b int) bool { 1420 if a == b { 1421 return true 1422 } 1423 switch a { 1424 case C_LCON: 1425 if b == C_RCON || b == C_NCON || b == C_SCON || b == C_RCON2A || b == C_RCON2S { 1426 return true 1427 } 1428 1429 case C_LACON: 1430 if b == C_RACON { 1431 return true 1432 } 1433 1434 case C_LFCON: 1435 if b == C_ZFCON || b == C_SFCON { 1436 return true 1437 } 1438 1439 case C_HFAUTO: 1440 return b == C_HAUTO || b == C_FAUTO 1441 1442 case C_FAUTO, C_HAUTO: 1443 return b == C_HFAUTO 1444 1445 case C_SAUTO: 1446 return cmp(C_HFAUTO, b) 1447 1448 case C_LAUTO: 1449 return cmp(C_SAUTO, b) 1450 1451 case C_HFOREG: 1452 return b == C_HOREG || b == C_FOREG 1453 1454 case C_FOREG, C_HOREG: 1455 return b == C_HFOREG 1456 1457 case C_SROREG: 1458 return cmp(C_SOREG, b) || cmp(C_ROREG, b) 1459 1460 case C_SOREG, C_ROREG: 1461 return b == C_SROREG || cmp(C_HFOREG, b) 1462 1463 case C_LOREG: 1464 return cmp(C_SROREG, b) 1465 1466 case C_LBRA: 1467 if b == C_SBRA { 1468 return true 1469 } 1470 1471 case C_HREG: 1472 return cmp(C_SP, b) || cmp(C_PC, b) 1473 } 1474 1475 return false 1476 } 1477 1478 type ocmp []Optab 1479 1480 func (x ocmp) Len() int { 1481 return len(x) 1482 } 1483 1484 func (x ocmp) Swap(i, j int) { 1485 x[i], x[j] = x[j], x[i] 1486 } 1487 1488 func (x ocmp) Less(i, j int) bool { 1489 p1 := &x[i] 1490 p2 := &x[j] 1491 n := int(p1.as) - int(p2.as) 1492 if n != 0 { 1493 return n < 0 1494 } 1495 n = int(p1.a1) - int(p2.a1) 1496 if n != 0 { 1497 return n < 0 1498 } 1499 n = int(p1.a2) - int(p2.a2) 1500 if n != 0 { 1501 return n < 0 1502 } 1503 n = int(p1.a3) - int(p2.a3) 1504 if n != 0 { 1505 return n < 0 1506 } 1507 return false 1508 } 1509 1510 func opset(a, b0 obj.As) { 1511 oprange[a&obj.AMask] = oprange[b0] 1512 } 1513 1514 func buildop(ctxt *obj.Link) { 1515 if oprange[AAND&obj.AMask] != nil { 1516 // Already initialized; stop now. 1517 // This happens in the cmd/asm tests, 1518 // each of which re-initializes the arch. 1519 return 1520 } 1521 1522 deferreturn = ctxt.Lookup("runtime.deferreturn") 1523 1524 symdiv = ctxt.Lookup("runtime._div") 1525 symdivu = ctxt.Lookup("runtime._divu") 1526 symmod = ctxt.Lookup("runtime._mod") 1527 symmodu = ctxt.Lookup("runtime._modu") 1528 1529 var n int 1530 1531 for i := 0; i < C_GOK; i++ { 1532 for n = 0; n < C_GOK; n++ { 1533 if cmp(n, i) { 1534 xcmp[i][n] = true 1535 } 1536 } 1537 } 1538 for n = 0; optab[n].as != obj.AXXX; n++ { 1539 if optab[n].flag&LPCREL != 0 { 1540 if ctxt.Flag_shared { 1541 optab[n].size += int8(optab[n].pcrelsiz) 1542 } else { 1543 optab[n].flag &^= LPCREL 1544 } 1545 } 1546 } 1547 1548 sort.Sort(ocmp(optab[:n])) 1549 for i := 0; i < n; i++ { 1550 r := optab[i].as 1551 r0 := r & obj.AMask 1552 start := i 1553 for optab[i].as == r { 1554 i++ 1555 } 1556 oprange[r0] = optab[start:i] 1557 i-- 1558 1559 switch r { 1560 default: 1561 ctxt.Diag("unknown op in build: %v", r) 1562 log.Fatalf("bad code") 1563 1564 case AADD: 1565 opset(ASUB, r0) 1566 opset(ARSB, r0) 1567 opset(AADC, r0) 1568 opset(ASBC, r0) 1569 opset(ARSC, r0) 1570 1571 case AORR: 1572 opset(AEOR, r0) 1573 opset(ABIC, r0) 1574 1575 case ACMP: 1576 opset(ATEQ, r0) 1577 opset(ACMN, r0) 1578 opset(ATST, r0) 1579 1580 case AMVN: 1581 break 1582 1583 case ABEQ: 1584 opset(ABNE, r0) 1585 opset(ABCS, r0) 1586 opset(ABHS, r0) 1587 opset(ABCC, r0) 1588 opset(ABLO, r0) 1589 opset(ABMI, r0) 1590 opset(ABPL, r0) 1591 opset(ABVS, r0) 1592 opset(ABVC, r0) 1593 opset(ABHI, r0) 1594 opset(ABLS, r0) 1595 opset(ABGE, r0) 1596 opset(ABLT, r0) 1597 opset(ABGT, r0) 1598 opset(ABLE, r0) 1599 1600 case ASLL: 1601 opset(ASRL, r0) 1602 opset(ASRA, r0) 1603 1604 case AMUL: 1605 opset(AMULU, r0) 1606 1607 case ADIV: 1608 opset(AMOD, r0) 1609 opset(AMODU, r0) 1610 opset(ADIVU, r0) 1611 1612 case ADIVHW: 1613 opset(ADIVUHW, r0) 1614 1615 case AMOVW, 1616 AMOVB, 1617 AMOVBS, 1618 AMOVBU, 1619 AMOVH, 1620 AMOVHS, 1621 AMOVHU: 1622 break 1623 1624 case ASWPW: 1625 opset(ASWPBU, r0) 1626 1627 case AB, 1628 ABL, 1629 ABX, 1630 ABXRET, 1631 obj.ADUFFZERO, 1632 obj.ADUFFCOPY, 1633 ASWI, 1634 AWORD, 1635 AMOVM, 1636 ARFE, 1637 obj.ATEXT: 1638 break 1639 1640 case AADDF: 1641 opset(AADDD, r0) 1642 opset(ASUBF, r0) 1643 opset(ASUBD, r0) 1644 opset(AMULF, r0) 1645 opset(AMULD, r0) 1646 opset(ADIVF, r0) 1647 opset(ADIVD, r0) 1648 1649 case ANEGF: 1650 opset(ANEGD, r0) 1651 opset(ASQRTF, r0) 1652 opset(ASQRTD, r0) 1653 opset(AMOVFD, r0) 1654 opset(AMOVDF, r0) 1655 opset(AABSF, r0) 1656 opset(AABSD, r0) 1657 1658 case ACMPF: 1659 opset(ACMPD, r0) 1660 1661 case AMOVF: 1662 opset(AMOVD, r0) 1663 1664 case AMOVFW: 1665 opset(AMOVDW, r0) 1666 1667 case AMOVWF: 1668 opset(AMOVWD, r0) 1669 1670 case AMULL: 1671 opset(AMULAL, r0) 1672 opset(AMULLU, r0) 1673 opset(AMULALU, r0) 1674 1675 case AMULWT: 1676 opset(AMULWB, r0) 1677 opset(AMULBB, r0) 1678 opset(AMMUL, r0) 1679 1680 case AMULAWT: 1681 opset(AMULAWB, r0) 1682 opset(AMULABB, r0) 1683 opset(AMULA, r0) 1684 opset(AMULS, r0) 1685 opset(AMMULA, r0) 1686 opset(AMMULS, r0) 1687 1688 case ACLZ: 1689 opset(AREV, r0) 1690 opset(AREV16, r0) 1691 opset(AREVSH, r0) 1692 opset(ARBIT, r0) 1693 1694 case ALDREX, 1695 ASTREX, 1696 ALDREXD, 1697 ASTREXD, 1698 APLD, 1699 AAND, 1700 obj.AUNDEF, 1701 obj.AFUNCDATA, 1702 obj.APCDATA, 1703 obj.ANOP, 1704 ADATABUNDLE, 1705 ADATABUNDLEEND: 1706 break 1707 } 1708 } 1709 } 1710 1711 func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) { 1712 c.printp = p 1713 o1 := uint32(0) 1714 o2 := uint32(0) 1715 o3 := uint32(0) 1716 o4 := uint32(0) 1717 o5 := uint32(0) 1718 o6 := uint32(0) 1719 if false { /*debug['P']*/ 1720 fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_) 1721 } 1722 switch o.type_ { 1723 default: 1724 c.ctxt.Diag("%v: unknown asm %d", p, o.type_) 1725 1726 case 0: /* pseudo ops */ 1727 if false { /*debug['G']*/ 1728 fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name) 1729 } 1730 1731 case 1: /* op R,[R],R */ 1732 o1 = c.oprrr(p, p.As, int(p.Scond)) 1733 1734 rf := int(p.From.Reg) 1735 rt := int(p.To.Reg) 1736 r := int(p.Reg) 1737 if p.To.Type == obj.TYPE_NONE { 1738 rt = 0 1739 } 1740 if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN { 1741 r = 0 1742 } else if r == 0 { 1743 r = rt 1744 } 1745 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1746 1747 case 2: /* movbu $I,[R],R */ 1748 c.aclass(&p.From) 1749 1750 o1 = c.oprrr(p, p.As, int(p.Scond)) 1751 o1 |= uint32(immrot(uint32(c.instoffset))) 1752 rt := int(p.To.Reg) 1753 r := int(p.Reg) 1754 if p.To.Type == obj.TYPE_NONE { 1755 rt = 0 1756 } 1757 if p.As == AMOVW || p.As == AMVN { 1758 r = 0 1759 } else if r == 0 { 1760 r = rt 1761 } 1762 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1763 1764 case 106: /* op $I,R,R where I can be decomposed into 2 immediates */ 1765 c.aclass(&p.From) 1766 r := int(p.Reg) 1767 rt := int(p.To.Reg) 1768 if r == 0 { 1769 r = rt 1770 } 1771 x, y := immrot2a(uint32(c.instoffset)) 1772 var as2 obj.As 1773 switch p.As { 1774 case AADD, ASUB, AORR, AEOR, ABIC: 1775 as2 = p.As // ADD, SUB, ORR, EOR, BIC 1776 case ARSB: 1777 as2 = AADD // RSB -> RSB/ADD pair 1778 case AADC: 1779 as2 = AADD // ADC -> ADC/ADD pair 1780 case ASBC: 1781 as2 = ASUB // SBC -> SBC/SUB pair 1782 case ARSC: 1783 as2 = AADD // RSC -> RSC/ADD pair 1784 default: 1785 c.ctxt.Diag("unknown second op for %v", p) 1786 } 1787 o1 = c.oprrr(p, p.As, int(p.Scond)) 1788 o2 = c.oprrr(p, as2, int(p.Scond)) 1789 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1790 o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12 1791 o1 |= x 1792 o2 |= y 1793 1794 case 107: /* op $I,R,R where I can be decomposed into 2 immediates */ 1795 c.aclass(&p.From) 1796 r := int(p.Reg) 1797 rt := int(p.To.Reg) 1798 if r == 0 { 1799 r = rt 1800 } 1801 y, x := immrot2s(uint32(c.instoffset)) 1802 var as2 obj.As 1803 switch p.As { 1804 case AADD: 1805 as2 = ASUB // ADD -> ADD/SUB pair 1806 case ASUB: 1807 as2 = AADD // SUB -> SUB/ADD pair 1808 case ARSB: 1809 as2 = ASUB // RSB -> RSB/SUB pair 1810 case AADC: 1811 as2 = ASUB // ADC -> ADC/SUB pair 1812 case ASBC: 1813 as2 = AADD // SBC -> SBC/ADD pair 1814 case ARSC: 1815 as2 = ASUB // RSC -> RSC/SUB pair 1816 default: 1817 c.ctxt.Diag("unknown second op for %v", p) 1818 } 1819 o1 = c.oprrr(p, p.As, int(p.Scond)) 1820 o2 = c.oprrr(p, as2, int(p.Scond)) 1821 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1822 o2 |= (uint32(rt)&15)<<16 | (uint32(rt)&15)<<12 1823 o1 |= y 1824 o2 |= x 1825 1826 case 3: /* add R<<[IR],[R],R */ 1827 o1 = c.mov(p) 1828 1829 case 4: /* MOVW $off(R), R -> add $off,[R],R */ 1830 c.aclass(&p.From) 1831 if c.instoffset < 0 { 1832 o1 = c.oprrr(p, ASUB, int(p.Scond)) 1833 o1 |= uint32(immrot(uint32(-c.instoffset))) 1834 } else { 1835 o1 = c.oprrr(p, AADD, int(p.Scond)) 1836 o1 |= uint32(immrot(uint32(c.instoffset))) 1837 } 1838 r := int(p.From.Reg) 1839 if r == 0 { 1840 r = int(o.param) 1841 } 1842 o1 |= (uint32(r) & 15) << 16 1843 o1 |= (uint32(p.To.Reg) & 15) << 12 1844 1845 case 5: /* bra s */ 1846 o1 = c.opbra(p, p.As, int(p.Scond)) 1847 1848 v := int32(-8) 1849 if p.To.Sym != nil { 1850 rel := obj.Addrel(c.cursym) 1851 rel.Off = int32(c.pc) 1852 rel.Siz = 4 1853 rel.Sym = p.To.Sym 1854 v += int32(p.To.Offset) 1855 rel.Add = int64(o1) | (int64(v)>>2)&0xffffff 1856 rel.Type = objabi.R_CALLARM 1857 break 1858 } 1859 1860 if p.Pcond != nil { 1861 v = int32((p.Pcond.Pc - c.pc) - 8) 1862 } 1863 o1 |= (uint32(v) >> 2) & 0xffffff 1864 1865 case 6: /* b ,O(R) -> add $O,R,PC */ 1866 c.aclass(&p.To) 1867 1868 o1 = c.oprrr(p, AADD, int(p.Scond)) 1869 o1 |= uint32(immrot(uint32(c.instoffset))) 1870 o1 |= (uint32(p.To.Reg) & 15) << 16 1871 o1 |= (REGPC & 15) << 12 1872 1873 case 7: /* bl (R) -> blx R */ 1874 c.aclass(&p.To) 1875 1876 if c.instoffset != 0 { 1877 c.ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, c.instoffset) 1878 } 1879 o1 = c.oprrr(p, ABL, int(p.Scond)) 1880 o1 |= (uint32(p.To.Reg) & 15) << 0 1881 rel := obj.Addrel(c.cursym) 1882 rel.Off = int32(c.pc) 1883 rel.Siz = 0 1884 rel.Type = objabi.R_CALLIND 1885 1886 case 8: /* sll $c,[R],R -> mov (R<<$c),R */ 1887 c.aclass(&p.From) 1888 1889 o1 = c.oprrr(p, p.As, int(p.Scond)) 1890 r := int(p.Reg) 1891 if r == 0 { 1892 r = int(p.To.Reg) 1893 } 1894 o1 |= (uint32(r) & 15) << 0 1895 o1 |= uint32((c.instoffset & 31) << 7) 1896 o1 |= (uint32(p.To.Reg) & 15) << 12 1897 1898 case 9: /* sll R,[R],R -> mov (R<<R),R */ 1899 o1 = c.oprrr(p, p.As, int(p.Scond)) 1900 1901 r := int(p.Reg) 1902 if r == 0 { 1903 r = int(p.To.Reg) 1904 } 1905 o1 |= (uint32(r) & 15) << 0 1906 o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4 1907 o1 |= (uint32(p.To.Reg) & 15) << 12 1908 1909 case 10: /* swi [$con] */ 1910 o1 = c.oprrr(p, p.As, int(p.Scond)) 1911 1912 if p.To.Type != obj.TYPE_NONE { 1913 c.aclass(&p.To) 1914 o1 |= uint32(c.instoffset & 0xffffff) 1915 } 1916 1917 case 11: /* word */ 1918 c.aclass(&p.To) 1919 1920 o1 = uint32(c.instoffset) 1921 if p.To.Sym != nil { 1922 // This case happens with words generated 1923 // in the PC stream as part of the literal pool (c.pool). 1924 rel := obj.Addrel(c.cursym) 1925 1926 rel.Off = int32(c.pc) 1927 rel.Siz = 4 1928 rel.Sym = p.To.Sym 1929 rel.Add = p.To.Offset 1930 1931 if c.ctxt.Flag_shared { 1932 if p.To.Name == obj.NAME_GOTREF { 1933 rel.Type = objabi.R_GOTPCREL 1934 } else { 1935 rel.Type = objabi.R_PCREL 1936 } 1937 rel.Add += c.pc - p.Rel.Pc - 8 1938 } else { 1939 rel.Type = objabi.R_ADDR 1940 } 1941 o1 = 0 1942 } 1943 1944 case 12: /* movw $lcon, reg */ 1945 if o.a1 == C_SCON { 1946 o1 = c.omvs(p, &p.From, int(p.To.Reg)) 1947 } else { 1948 o1 = c.omvl(p, &p.From, int(p.To.Reg)) 1949 } 1950 1951 if o.flag&LPCREL != 0 { 1952 o2 = c.oprrr(p, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12 1953 } 1954 1955 case 13: /* op $lcon, [R], R */ 1956 if o.a1 == C_SCON { 1957 o1 = c.omvs(p, &p.From, REGTMP) 1958 } else { 1959 o1 = c.omvl(p, &p.From, REGTMP) 1960 } 1961 1962 if o1 == 0 { 1963 break 1964 } 1965 o2 = c.oprrr(p, p.As, int(p.Scond)) 1966 o2 |= REGTMP & 15 1967 r := int(p.Reg) 1968 if p.As == AMOVW || p.As == AMVN { 1969 r = 0 1970 } else if r == 0 { 1971 r = int(p.To.Reg) 1972 } 1973 o2 |= (uint32(r) & 15) << 16 1974 if p.To.Type != obj.TYPE_NONE { 1975 o2 |= (uint32(p.To.Reg) & 15) << 12 1976 } 1977 1978 case 14: /* movb/movbu/movh/movhu R,R */ 1979 o1 = c.oprrr(p, ASLL, int(p.Scond)) 1980 1981 if p.As == AMOVBU || p.As == AMOVHU { 1982 o2 = c.oprrr(p, ASRL, int(p.Scond)) 1983 } else { 1984 o2 = c.oprrr(p, ASRA, int(p.Scond)) 1985 } 1986 1987 r := int(p.To.Reg) 1988 o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12 1989 o2 |= uint32(r)&15 | (uint32(r)&15)<<12 1990 if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU { 1991 o1 |= 24 << 7 1992 o2 |= 24 << 7 1993 } else { 1994 o1 |= 16 << 7 1995 o2 |= 16 << 7 1996 } 1997 1998 case 15: /* mul r,[r,]r */ 1999 o1 = c.oprrr(p, p.As, int(p.Scond)) 2000 2001 rf := int(p.From.Reg) 2002 rt := int(p.To.Reg) 2003 r := int(p.Reg) 2004 if r == 0 { 2005 r = rt 2006 } 2007 if rt == r { 2008 r = rf 2009 rf = rt 2010 } 2011 2012 if false { 2013 if rt == r || rf == REGPC&15 || r == REGPC&15 || rt == REGPC&15 { 2014 c.ctxt.Diag("%v: bad registers in MUL", p) 2015 } 2016 } 2017 2018 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 2019 2020 case 16: /* div r,[r,]r */ 2021 o1 = 0xf << 28 2022 2023 o2 = 0 2024 2025 case 17: 2026 o1 = c.oprrr(p, p.As, int(p.Scond)) 2027 rf := int(p.From.Reg) 2028 rt := int(p.To.Reg) 2029 rt2 := int(p.To.Offset) 2030 r := int(p.Reg) 2031 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12 2032 2033 case 20: /* mov/movb/movbu R,O(R) */ 2034 c.aclass(&p.To) 2035 2036 r := int(p.To.Reg) 2037 if r == 0 { 2038 r = int(o.param) 2039 } 2040 o1 = c.osr(p.As, int(p.From.Reg), int32(c.instoffset), r, int(p.Scond)) 2041 2042 case 21: /* mov/movbu O(R),R -> lr */ 2043 c.aclass(&p.From) 2044 2045 r := int(p.From.Reg) 2046 if r == 0 { 2047 r = int(o.param) 2048 } 2049 o1 = c.olr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond)) 2050 if p.As != AMOVW { 2051 o1 |= 1 << 22 2052 } 2053 2054 case 30: /* mov/movb/movbu R,L(R) */ 2055 o1 = c.omvl(p, &p.To, REGTMP) 2056 2057 if o1 == 0 { 2058 break 2059 } 2060 r := int(p.To.Reg) 2061 if r == 0 { 2062 r = int(o.param) 2063 } 2064 o2 = c.osrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond)) 2065 if p.As != AMOVW { 2066 o2 |= 1 << 22 2067 } 2068 2069 case 31: /* mov/movbu L(R),R -> lr[b] */ 2070 o1 = c.omvl(p, &p.From, REGTMP) 2071 2072 if o1 == 0 { 2073 break 2074 } 2075 r := int(p.From.Reg) 2076 if r == 0 { 2077 r = int(o.param) 2078 } 2079 o2 = c.olrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond)) 2080 if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { 2081 o2 |= 1 << 22 2082 } 2083 2084 case 34: /* mov $lacon,R */ 2085 o1 = c.omvl(p, &p.From, REGTMP) 2086 2087 if o1 == 0 { 2088 break 2089 } 2090 2091 o2 = c.oprrr(p, AADD, int(p.Scond)) 2092 o2 |= REGTMP & 15 2093 r := int(p.From.Reg) 2094 if r == 0 { 2095 r = int(o.param) 2096 } 2097 o2 |= (uint32(r) & 15) << 16 2098 if p.To.Type != obj.TYPE_NONE { 2099 o2 |= (uint32(p.To.Reg) & 15) << 12 2100 } 2101 2102 case 35: /* mov PSR,R */ 2103 o1 = 2<<23 | 0xf<<16 | 0<<0 2104 2105 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2106 o1 |= (uint32(p.From.Reg) & 1) << 22 2107 o1 |= (uint32(p.To.Reg) & 15) << 12 2108 2109 case 36: /* mov R,PSR */ 2110 o1 = 2<<23 | 0x2cf<<12 | 0<<4 2111 2112 if p.Scond&C_FBIT != 0 { 2113 o1 ^= 0x010 << 12 2114 } 2115 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2116 o1 |= (uint32(p.To.Reg) & 1) << 22 2117 o1 |= (uint32(p.From.Reg) & 15) << 0 2118 2119 case 37: /* mov $con,PSR */ 2120 c.aclass(&p.From) 2121 2122 o1 = 2<<23 | 0x2cf<<12 | 0<<4 2123 if p.Scond&C_FBIT != 0 { 2124 o1 ^= 0x010 << 12 2125 } 2126 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2127 o1 |= uint32(immrot(uint32(c.instoffset))) 2128 o1 |= (uint32(p.To.Reg) & 1) << 22 2129 o1 |= (uint32(p.From.Reg) & 15) << 0 2130 2131 case 38, 39: 2132 switch o.type_ { 2133 case 38: /* movm $con,oreg -> stm */ 2134 o1 = 0x4 << 25 2135 2136 o1 |= uint32(p.From.Offset & 0xffff) 2137 o1 |= (uint32(p.To.Reg) & 15) << 16 2138 c.aclass(&p.To) 2139 2140 case 39: /* movm oreg,$con -> ldm */ 2141 o1 = 0x4<<25 | 1<<20 2142 2143 o1 |= uint32(p.To.Offset & 0xffff) 2144 o1 |= (uint32(p.From.Reg) & 15) << 16 2145 c.aclass(&p.From) 2146 } 2147 2148 if c.instoffset != 0 { 2149 c.ctxt.Diag("offset must be zero in MOVM; %v", p) 2150 } 2151 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2152 if p.Scond&C_PBIT != 0 { 2153 o1 |= 1 << 24 2154 } 2155 if p.Scond&C_UBIT != 0 { 2156 o1 |= 1 << 23 2157 } 2158 if p.Scond&C_WBIT != 0 { 2159 o1 |= 1 << 21 2160 } 2161 2162 case 40: /* swp oreg,reg,reg */ 2163 c.aclass(&p.From) 2164 2165 if c.instoffset != 0 { 2166 c.ctxt.Diag("offset must be zero in SWP") 2167 } 2168 o1 = 0x2<<23 | 0x9<<4 2169 if p.As != ASWPW { 2170 o1 |= 1 << 22 2171 } 2172 o1 |= (uint32(p.From.Reg) & 15) << 16 2173 o1 |= (uint32(p.Reg) & 15) << 0 2174 o1 |= (uint32(p.To.Reg) & 15) << 12 2175 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2176 2177 case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ 2178 o1 = 0xe8fd8000 2179 2180 case 50: /* floating point store */ 2181 v := c.regoff(&p.To) 2182 2183 r := int(p.To.Reg) 2184 if r == 0 { 2185 r = int(o.param) 2186 } 2187 o1 = c.ofsr(p.As, int(p.From.Reg), v, r, int(p.Scond), p) 2188 2189 case 51: /* floating point load */ 2190 v := c.regoff(&p.From) 2191 2192 r := int(p.From.Reg) 2193 if r == 0 { 2194 r = int(o.param) 2195 } 2196 o1 = c.ofsr(p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20 2197 2198 case 52: /* floating point store, int32 offset UGLY */ 2199 o1 = c.omvl(p, &p.To, REGTMP) 2200 2201 if o1 == 0 { 2202 break 2203 } 2204 r := int(p.To.Reg) 2205 if r == 0 { 2206 r = int(o.param) 2207 } 2208 o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 2209 o3 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p) 2210 2211 case 53: /* floating point load, int32 offset UGLY */ 2212 o1 = c.omvl(p, &p.From, REGTMP) 2213 2214 if o1 == 0 { 2215 break 2216 } 2217 r := int(p.From.Reg) 2218 if r == 0 { 2219 r = int(o.param) 2220 } 2221 o2 = c.oprrr(p, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 2222 o3 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 2223 2224 case 54: /* floating point arith */ 2225 o1 = c.oprrr(p, p.As, int(p.Scond)) 2226 2227 rf := int(p.From.Reg) 2228 rt := int(p.To.Reg) 2229 r := int(p.Reg) 2230 if r == 0 { 2231 r = rt 2232 } 2233 2234 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 2235 2236 case 55: /* negf freg, freg */ 2237 o1 = c.oprrr(p, p.As, int(p.Scond)) 2238 2239 rf := int(p.From.Reg) 2240 rt := int(p.To.Reg) 2241 2242 o1 |= (uint32(rf)&15)<<0 | (uint32(rt)&15)<<12 2243 2244 case 56: /* move to FP[CS]R */ 2245 o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xee1<<16 | 0xa1<<4 2246 2247 o1 |= (uint32(p.From.Reg) & 15) << 12 2248 2249 case 57: /* move from FP[CS]R */ 2250 o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xef1<<16 | 0xa1<<4 2251 2252 o1 |= (uint32(p.To.Reg) & 15) << 12 2253 2254 case 58: /* movbu R,R */ 2255 o1 = c.oprrr(p, AAND, int(p.Scond)) 2256 2257 o1 |= uint32(immrot(0xff)) 2258 rt := int(p.To.Reg) 2259 r := int(p.From.Reg) 2260 if p.To.Type == obj.TYPE_NONE { 2261 rt = 0 2262 } 2263 if r == 0 { 2264 r = rt 2265 } 2266 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 2267 2268 case 59: /* movw/bu R<<I(R),R -> ldr indexed */ 2269 if p.From.Reg == 0 { 2270 if p.As != AMOVW { 2271 c.ctxt.Diag("byte MOV from shifter operand") 2272 } 2273 o1 = c.mov(p) 2274 break 2275 } 2276 2277 if p.From.Offset&(1<<4) != 0 { 2278 c.ctxt.Diag("bad shift in LDR") 2279 } 2280 o1 = c.olrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) 2281 if p.As == AMOVBU { 2282 o1 |= 1 << 22 2283 } 2284 2285 case 60: /* movb R(R),R -> ldrsb indexed */ 2286 if p.From.Reg == 0 { 2287 c.ctxt.Diag("byte MOV from shifter operand") 2288 o1 = c.mov(p) 2289 break 2290 } 2291 2292 if p.From.Offset&(^0xf) != 0 { 2293 c.ctxt.Diag("bad shift: %v", p) 2294 } 2295 o1 = c.olhrr(int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) 2296 o1 ^= 1<<5 | 1<<6 2297 if p.Scond&C_UBIT != 0 { 2298 o1 &^= 1 << 23 2299 } 2300 2301 case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ 2302 if p.To.Reg == 0 { 2303 c.ctxt.Diag("MOV to shifter operand") 2304 } 2305 o1 = c.osrr(int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond)) 2306 if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU { 2307 o1 |= 1 << 22 2308 } 2309 2310 /* reloc ops */ 2311 case 64: /* mov/movb/movbu R,addr */ 2312 o1 = c.omvl(p, &p.To, REGTMP) 2313 2314 if o1 == 0 { 2315 break 2316 } 2317 o2 = c.osr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond)) 2318 if o.flag&LPCREL != 0 { 2319 o3 = o2 2320 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2321 } 2322 2323 case 65: /* mov/movbu addr,R */ 2324 o1 = c.omvl(p, &p.From, REGTMP) 2325 2326 if o1 == 0 { 2327 break 2328 } 2329 o2 = c.olr(0, REGTMP, int(p.To.Reg), int(p.Scond)) 2330 if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { 2331 o2 |= 1 << 22 2332 } 2333 if o.flag&LPCREL != 0 { 2334 o3 = o2 2335 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2336 } 2337 2338 case 101: /* movw tlsvar,R, local exec*/ 2339 if p.Scond&C_SCOND != C_SCOND_NONE { 2340 c.ctxt.Diag("conditional tls") 2341 } 2342 o1 = c.omvl(p, &p.From, int(p.To.Reg)) 2343 2344 case 102: /* movw tlsvar,R, initial exec*/ 2345 if p.Scond&C_SCOND != C_SCOND_NONE { 2346 c.ctxt.Diag("conditional tls") 2347 } 2348 o1 = c.omvl(p, &p.From, int(p.To.Reg)) 2349 o2 = c.olrr(int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond)) 2350 2351 case 103: /* word tlsvar, local exec */ 2352 if p.To.Sym == nil { 2353 c.ctxt.Diag("nil sym in tls %v", p) 2354 } 2355 if p.To.Offset != 0 { 2356 c.ctxt.Diag("offset against tls var in %v", p) 2357 } 2358 // This case happens with words generated in the PC stream as part of 2359 // the literal c.pool. 2360 rel := obj.Addrel(c.cursym) 2361 2362 rel.Off = int32(c.pc) 2363 rel.Siz = 4 2364 rel.Sym = p.To.Sym 2365 rel.Type = objabi.R_TLS_LE 2366 o1 = 0 2367 2368 case 104: /* word tlsvar, initial exec */ 2369 if p.To.Sym == nil { 2370 c.ctxt.Diag("nil sym in tls %v", p) 2371 } 2372 if p.To.Offset != 0 { 2373 c.ctxt.Diag("offset against tls var in %v", p) 2374 } 2375 rel := obj.Addrel(c.cursym) 2376 rel.Off = int32(c.pc) 2377 rel.Siz = 4 2378 rel.Sym = p.To.Sym 2379 rel.Type = objabi.R_TLS_IE 2380 rel.Add = c.pc - p.Rel.Pc - 8 - int64(rel.Siz) 2381 2382 case 68: /* floating point store -> ADDR */ 2383 o1 = c.omvl(p, &p.To, REGTMP) 2384 2385 if o1 == 0 { 2386 break 2387 } 2388 o2 = c.ofsr(p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p) 2389 if o.flag&LPCREL != 0 { 2390 o3 = o2 2391 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2392 } 2393 2394 case 69: /* floating point load <- ADDR */ 2395 o1 = c.omvl(p, &p.From, REGTMP) 2396 2397 if o1 == 0 { 2398 break 2399 } 2400 o2 = c.ofsr(p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 2401 if o.flag&LPCREL != 0 { 2402 o3 = o2 2403 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2404 } 2405 2406 /* ArmV4 ops: */ 2407 case 70: /* movh/movhu R,O(R) -> strh */ 2408 c.aclass(&p.To) 2409 2410 r := int(p.To.Reg) 2411 if r == 0 { 2412 r = int(o.param) 2413 } 2414 o1 = c.oshr(int(p.From.Reg), int32(c.instoffset), r, int(p.Scond)) 2415 2416 case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ 2417 c.aclass(&p.From) 2418 2419 r := int(p.From.Reg) 2420 if r == 0 { 2421 r = int(o.param) 2422 } 2423 o1 = c.olhr(int32(c.instoffset), r, int(p.To.Reg), int(p.Scond)) 2424 if p.As == AMOVB || p.As == AMOVBS { 2425 o1 ^= 1<<5 | 1<<6 2426 } else if p.As == AMOVH || p.As == AMOVHS { 2427 o1 ^= (1 << 6) 2428 } 2429 2430 case 72: /* movh/movhu R,L(R) -> strh */ 2431 o1 = c.omvl(p, &p.To, REGTMP) 2432 2433 if o1 == 0 { 2434 break 2435 } 2436 r := int(p.To.Reg) 2437 if r == 0 { 2438 r = int(o.param) 2439 } 2440 o2 = c.oshrr(int(p.From.Reg), REGTMP&15, r, int(p.Scond)) 2441 2442 case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ 2443 o1 = c.omvl(p, &p.From, REGTMP) 2444 2445 if o1 == 0 { 2446 break 2447 } 2448 r := int(p.From.Reg) 2449 if r == 0 { 2450 r = int(o.param) 2451 } 2452 o2 = c.olhrr(REGTMP&15, r, int(p.To.Reg), int(p.Scond)) 2453 if p.As == AMOVB || p.As == AMOVBS { 2454 o2 ^= 1<<5 | 1<<6 2455 } else if p.As == AMOVH || p.As == AMOVHS { 2456 o2 ^= (1 << 6) 2457 } 2458 2459 case 74: /* bx $I */ 2460 c.ctxt.Diag("ABX $I") 2461 2462 case 75: /* bx O(R) */ 2463 c.aclass(&p.To) 2464 2465 if c.instoffset != 0 { 2466 c.ctxt.Diag("non-zero offset in ABX") 2467 } 2468 2469 /* 2470 o1 = c.oprrr(p, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR 2471 o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0); // BX R 2472 */ 2473 // p->to.reg may be REGLINK 2474 o1 = c.oprrr(p, AADD, int(p.Scond)) 2475 2476 o1 |= uint32(immrot(uint32(c.instoffset))) 2477 o1 |= (uint32(p.To.Reg) & 15) << 16 2478 o1 |= (REGTMP & 15) << 12 2479 o2 = c.oprrr(p, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR 2480 o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15 // BX Rtmp 2481 2482 case 76: /* bx O(R) when returning from fn*/ 2483 c.ctxt.Diag("ABXRET") 2484 2485 case 77: /* ldrex oreg,reg */ 2486 c.aclass(&p.From) 2487 2488 if c.instoffset != 0 { 2489 c.ctxt.Diag("offset must be zero in LDREX") 2490 } 2491 o1 = 0x19<<20 | 0xf9f 2492 o1 |= (uint32(p.From.Reg) & 15) << 16 2493 o1 |= (uint32(p.To.Reg) & 15) << 12 2494 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2495 2496 case 78: /* strex reg,oreg,reg */ 2497 c.aclass(&p.From) 2498 2499 if c.instoffset != 0 { 2500 c.ctxt.Diag("offset must be zero in STREX") 2501 } 2502 o1 = 0x18<<20 | 0xf90 2503 o1 |= (uint32(p.From.Reg) & 15) << 16 2504 o1 |= (uint32(p.Reg) & 15) << 0 2505 o1 |= (uint32(p.To.Reg) & 15) << 12 2506 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2507 2508 case 80: /* fmov zfcon,freg */ 2509 if p.As == AMOVD { 2510 o1 = 0xeeb00b00 // VMOV imm 64 2511 o2 = c.oprrr(p, ASUBD, int(p.Scond)) 2512 } else { 2513 o1 = 0x0eb00a00 // VMOV imm 32 2514 o2 = c.oprrr(p, ASUBF, int(p.Scond)) 2515 } 2516 2517 v := int32(0x70) // 1.0 2518 r := (int(p.To.Reg) & 15) << 0 2519 2520 // movf $1.0, r 2521 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2522 2523 o1 |= (uint32(r) & 15) << 12 2524 o1 |= (uint32(v) & 0xf) << 0 2525 o1 |= (uint32(v) & 0xf0) << 12 2526 2527 // subf r,r,r 2528 o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12 2529 2530 case 81: /* fmov sfcon,freg */ 2531 o1 = 0x0eb00a00 // VMOV imm 32 2532 if p.As == AMOVD { 2533 o1 = 0xeeb00b00 // VMOV imm 64 2534 } 2535 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2536 o1 |= (uint32(p.To.Reg) & 15) << 12 2537 v := int32(c.chipfloat5(p.From.Val.(float64))) 2538 o1 |= (uint32(v) & 0xf) << 0 2539 o1 |= (uint32(v) & 0xf0) << 12 2540 2541 case 82: /* fcmp freg,freg, */ 2542 o1 = c.oprrr(p, p.As, int(p.Scond)) 2543 2544 o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0 2545 o2 = 0x0ef1fa10 // VMRS R15 2546 o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2547 2548 case 83: /* fcmp freg,, */ 2549 o1 = c.oprrr(p, p.As, int(p.Scond)) 2550 2551 o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16 2552 o2 = 0x0ef1fa10 // VMRS R15 2553 o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2554 2555 case 84: /* movfw freg,freg - truncate float-to-fix */ 2556 o1 = c.oprrr(p, p.As, int(p.Scond)) 2557 2558 o1 |= (uint32(p.From.Reg) & 15) << 0 2559 o1 |= (uint32(p.To.Reg) & 15) << 12 2560 2561 case 85: /* movwf freg,freg - fix-to-float */ 2562 o1 = c.oprrr(p, p.As, int(p.Scond)) 2563 2564 o1 |= (uint32(p.From.Reg) & 15) << 0 2565 o1 |= (uint32(p.To.Reg) & 15) << 12 2566 2567 // macro for movfw freg,FTMP; movw FTMP,reg 2568 case 86: /* movfw freg,reg - truncate float-to-fix */ 2569 o1 = c.oprrr(p, p.As, int(p.Scond)) 2570 2571 o1 |= (uint32(p.From.Reg) & 15) << 0 2572 o1 |= (FREGTMP & 15) << 12 2573 o2 = c.oprrr(p, -AMOVFW, int(p.Scond)) 2574 o2 |= (FREGTMP & 15) << 16 2575 o2 |= (uint32(p.To.Reg) & 15) << 12 2576 2577 // macro for movw reg,FTMP; movwf FTMP,freg 2578 case 87: /* movwf reg,freg - fix-to-float */ 2579 o1 = c.oprrr(p, -AMOVWF, int(p.Scond)) 2580 2581 o1 |= (uint32(p.From.Reg) & 15) << 12 2582 o1 |= (FREGTMP & 15) << 16 2583 o2 = c.oprrr(p, p.As, int(p.Scond)) 2584 o2 |= (FREGTMP & 15) << 0 2585 o2 |= (uint32(p.To.Reg) & 15) << 12 2586 2587 case 88: /* movw reg,freg */ 2588 o1 = c.oprrr(p, -AMOVWF, int(p.Scond)) 2589 2590 o1 |= (uint32(p.From.Reg) & 15) << 12 2591 o1 |= (uint32(p.To.Reg) & 15) << 16 2592 2593 case 89: /* movw freg,reg */ 2594 o1 = c.oprrr(p, -AMOVFW, int(p.Scond)) 2595 2596 o1 |= (uint32(p.From.Reg) & 15) << 16 2597 o1 |= (uint32(p.To.Reg) & 15) << 12 2598 2599 case 91: /* ldrexd oreg,reg */ 2600 c.aclass(&p.From) 2601 2602 if c.instoffset != 0 { 2603 c.ctxt.Diag("offset must be zero in LDREX") 2604 } 2605 o1 = 0x1b<<20 | 0xf9f 2606 o1 |= (uint32(p.From.Reg) & 15) << 16 2607 o1 |= (uint32(p.To.Reg) & 15) << 12 2608 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2609 2610 case 92: /* strexd reg,oreg,reg */ 2611 c.aclass(&p.From) 2612 2613 if c.instoffset != 0 { 2614 c.ctxt.Diag("offset must be zero in STREX") 2615 } 2616 o1 = 0x1a<<20 | 0xf90 2617 o1 |= (uint32(p.From.Reg) & 15) << 16 2618 o1 |= (uint32(p.Reg) & 15) << 0 2619 o1 |= (uint32(p.To.Reg) & 15) << 12 2620 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2621 2622 case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ 2623 o1 = c.omvl(p, &p.From, REGTMP) 2624 2625 if o1 == 0 { 2626 break 2627 } 2628 o2 = c.olhr(0, REGTMP, int(p.To.Reg), int(p.Scond)) 2629 if p.As == AMOVB || p.As == AMOVBS { 2630 o2 ^= 1<<5 | 1<<6 2631 } else if p.As == AMOVH || p.As == AMOVHS { 2632 o2 ^= (1 << 6) 2633 } 2634 if o.flag&LPCREL != 0 { 2635 o3 = o2 2636 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2637 } 2638 2639 case 94: /* movh/movhu R,addr -> strh */ 2640 o1 = c.omvl(p, &p.To, REGTMP) 2641 2642 if o1 == 0 { 2643 break 2644 } 2645 o2 = c.oshr(int(p.From.Reg), 0, REGTMP, int(p.Scond)) 2646 if o.flag&LPCREL != 0 { 2647 o3 = o2 2648 o2 = c.oprrr(p, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2649 } 2650 2651 case 95: /* PLD off(reg) */ 2652 o1 = 0xf5d0f000 2653 2654 o1 |= (uint32(p.From.Reg) & 15) << 16 2655 if p.From.Offset < 0 { 2656 o1 &^= (1 << 23) 2657 o1 |= uint32((-p.From.Offset) & 0xfff) 2658 } else { 2659 o1 |= uint32(p.From.Offset & 0xfff) 2660 } 2661 2662 // This is supposed to be something that stops execution. 2663 // It's not supposed to be reached, ever, but if it is, we'd 2664 // like to be able to tell how we got there. Assemble as 2665 // 0xf7fabcfd which is guaranteed to raise undefined instruction 2666 // exception. 2667 case 96: /* UNDEF */ 2668 o1 = 0xf7fabcfd 2669 2670 case 97: /* CLZ Rm, Rd */ 2671 o1 = c.oprrr(p, p.As, int(p.Scond)) 2672 2673 o1 |= (uint32(p.To.Reg) & 15) << 12 2674 o1 |= (uint32(p.From.Reg) & 15) << 0 2675 2676 case 98: /* MULW{T,B} Rs, Rm, Rd */ 2677 o1 = c.oprrr(p, p.As, int(p.Scond)) 2678 2679 o1 |= (uint32(p.To.Reg) & 15) << 16 2680 o1 |= (uint32(p.From.Reg) & 15) << 8 2681 o1 |= (uint32(p.Reg) & 15) << 0 2682 2683 case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ 2684 o1 = c.oprrr(p, p.As, int(p.Scond)) 2685 2686 o1 |= (uint32(p.To.Reg) & 15) << 16 2687 o1 |= (uint32(p.From.Reg) & 15) << 8 2688 o1 |= (uint32(p.Reg) & 15) << 0 2689 o1 |= uint32((p.To.Offset & 15) << 12) 2690 2691 // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle; 2692 // DATABUNDLEEND: zero width alignment marker 2693 case 100: 2694 if p.As == ADATABUNDLE { 2695 o1 = 0xe125be70 2696 } 2697 2698 case 105: /* divhw r,[r,]r */ 2699 o1 = c.oprrr(p, p.As, int(p.Scond)) 2700 rf := int(p.From.Reg) 2701 rt := int(p.To.Reg) 2702 r := int(p.Reg) 2703 if r == 0 { 2704 r = rt 2705 } 2706 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 2707 } 2708 2709 out[0] = o1 2710 out[1] = o2 2711 out[2] = o3 2712 out[3] = o4 2713 out[4] = o5 2714 out[5] = o6 2715 return 2716 } 2717 2718 func (c *ctxt5) mov(p *obj.Prog) uint32 { 2719 c.aclass(&p.From) 2720 o1 := c.oprrr(p, p.As, int(p.Scond)) 2721 o1 |= uint32(p.From.Offset) 2722 rt := int(p.To.Reg) 2723 if p.To.Type == obj.TYPE_NONE { 2724 rt = 0 2725 } 2726 r := int(p.Reg) 2727 if p.As == AMOVW || p.As == AMVN { 2728 r = 0 2729 } else if r == 0 { 2730 r = rt 2731 } 2732 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 2733 return o1 2734 } 2735 2736 func (c *ctxt5) oprrr(p *obj.Prog, a obj.As, sc int) uint32 { 2737 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2738 if sc&C_SBIT != 0 { 2739 o |= 1 << 20 2740 } 2741 switch a { 2742 case ADIVHW: 2743 return o | 0x71<<20 | 0xf<<12 | 0x1<<4 2744 case ADIVUHW: 2745 return o | 0x73<<20 | 0xf<<12 | 0x1<<4 2746 case AMMUL: 2747 return o | 0x75<<20 | 0xf<<12 | 0x1<<4 2748 case AMULS: 2749 return o | 0x6<<20 | 0x9<<4 2750 case AMMULA: 2751 return o | 0x75<<20 | 0x1<<4 2752 case AMMULS: 2753 return o | 0x75<<20 | 0xd<<4 2754 case AMULU, AMUL: 2755 return o | 0x0<<21 | 0x9<<4 2756 case AMULA: 2757 return o | 0x1<<21 | 0x9<<4 2758 case AMULLU: 2759 return o | 0x4<<21 | 0x9<<4 2760 case AMULL: 2761 return o | 0x6<<21 | 0x9<<4 2762 case AMULALU: 2763 return o | 0x5<<21 | 0x9<<4 2764 case AMULAL: 2765 return o | 0x7<<21 | 0x9<<4 2766 case AAND: 2767 return o | 0x0<<21 2768 case AEOR: 2769 return o | 0x1<<21 2770 case ASUB: 2771 return o | 0x2<<21 2772 case ARSB: 2773 return o | 0x3<<21 2774 case AADD: 2775 return o | 0x4<<21 2776 case AADC: 2777 return o | 0x5<<21 2778 case ASBC: 2779 return o | 0x6<<21 2780 case ARSC: 2781 return o | 0x7<<21 2782 case ATST: 2783 return o | 0x8<<21 | 1<<20 2784 case ATEQ: 2785 return o | 0x9<<21 | 1<<20 2786 case ACMP: 2787 return o | 0xa<<21 | 1<<20 2788 case ACMN: 2789 return o | 0xb<<21 | 1<<20 2790 case AORR: 2791 return o | 0xc<<21 2792 2793 case AMOVB, AMOVH, AMOVW: 2794 if sc&(C_PBIT|C_WBIT) != 0 { 2795 c.ctxt.Diag("invalid .P/.W suffix: %v", p) 2796 } 2797 return o | 0xd<<21 2798 case ABIC: 2799 return o | 0xe<<21 2800 case AMVN: 2801 return o | 0xf<<21 2802 case ASLL: 2803 return o | 0xd<<21 | 0<<5 2804 case ASRL: 2805 return o | 0xd<<21 | 1<<5 2806 case ASRA: 2807 return o | 0xd<<21 | 2<<5 2808 case ASWI: 2809 return o | 0xf<<24 2810 2811 case AADDD: 2812 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4 2813 case AADDF: 2814 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4 2815 case ASUBD: 2816 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4 2817 case ASUBF: 2818 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4 2819 case AMULD: 2820 return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4 2821 case AMULF: 2822 return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4 2823 case ADIVD: 2824 return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4 2825 case ADIVF: 2826 return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4 2827 case ASQRTD: 2828 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4 2829 case ASQRTF: 2830 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4 2831 case AABSD: 2832 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4 2833 case AABSF: 2834 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4 2835 case ANEGD: 2836 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0x4<<4 2837 case ANEGF: 2838 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0x4<<4 2839 case ACMPD: 2840 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4 2841 case ACMPF: 2842 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4 2843 2844 case AMOVF: 2845 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4 2846 case AMOVD: 2847 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4 2848 2849 case AMOVDF: 2850 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof 2851 case AMOVFD: 2852 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof 2853 2854 case AMOVWF: 2855 if sc&C_UBIT == 0 { 2856 o |= 1 << 7 /* signed */ 2857 } 2858 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double 2859 2860 case AMOVWD: 2861 if sc&C_UBIT == 0 { 2862 o |= 1 << 7 /* signed */ 2863 } 2864 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double 2865 2866 case AMOVFW: 2867 if sc&C_UBIT == 0 { 2868 o |= 1 << 16 /* signed */ 2869 } 2870 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc 2871 2872 case AMOVDW: 2873 if sc&C_UBIT == 0 { 2874 o |= 1 << 16 /* signed */ 2875 } 2876 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc 2877 2878 case -AMOVWF: // copy WtoF 2879 return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4 2880 2881 case -AMOVFW: // copy FtoW 2882 return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4 2883 2884 case -ACMP: // cmp imm 2885 return o | 0x3<<24 | 0x5<<20 2886 2887 // CLZ doesn't support .nil 2888 case ACLZ: 2889 return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4 2890 2891 case AREV: 2892 return o&(0xf<<28) | 0x6bf<<16 | 0xf3<<4 2893 2894 case AREV16: 2895 return o&(0xf<<28) | 0x6bf<<16 | 0xfb<<4 2896 2897 case AREVSH: 2898 return o&(0xf<<28) | 0x6ff<<16 | 0xfb<<4 2899 2900 case ARBIT: 2901 return o&(0xf<<28) | 0x6ff<<16 | 0xf3<<4 2902 2903 case AMULWT: 2904 return o&(0xf<<28) | 0x12<<20 | 0xe<<4 2905 2906 case AMULWB: 2907 return o&(0xf<<28) | 0x12<<20 | 0xa<<4 2908 2909 case AMULBB: 2910 return o&(0xf<<28) | 0x16<<20 | 0x8<<4 2911 2912 case AMULAWT: 2913 return o&(0xf<<28) | 0x12<<20 | 0xc<<4 2914 2915 case AMULAWB: 2916 return o&(0xf<<28) | 0x12<<20 | 0x8<<4 2917 2918 case AMULABB: 2919 return o&(0xf<<28) | 0x10<<20 | 0x8<<4 2920 2921 case ABL: // BLX REG 2922 return o&(0xf<<28) | 0x12fff3<<4 2923 } 2924 2925 c.ctxt.Diag("%v: bad rrr %d", p, a) 2926 return 0 2927 } 2928 2929 func (c *ctxt5) opbra(p *obj.Prog, a obj.As, sc int) uint32 { 2930 sc &= C_SCOND 2931 sc ^= C_SCOND_XOR 2932 if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY { 2933 return uint32(sc)<<28 | 0x5<<25 | 0x1<<24 2934 } 2935 if sc != 0xe { 2936 c.ctxt.Diag("%v: .COND on bcond instruction", p) 2937 } 2938 switch a { 2939 case ABEQ: 2940 return 0x0<<28 | 0x5<<25 2941 case ABNE: 2942 return 0x1<<28 | 0x5<<25 2943 case ABCS: 2944 return 0x2<<28 | 0x5<<25 2945 case ABHS: 2946 return 0x2<<28 | 0x5<<25 2947 case ABCC: 2948 return 0x3<<28 | 0x5<<25 2949 case ABLO: 2950 return 0x3<<28 | 0x5<<25 2951 case ABMI: 2952 return 0x4<<28 | 0x5<<25 2953 case ABPL: 2954 return 0x5<<28 | 0x5<<25 2955 case ABVS: 2956 return 0x6<<28 | 0x5<<25 2957 case ABVC: 2958 return 0x7<<28 | 0x5<<25 2959 case ABHI: 2960 return 0x8<<28 | 0x5<<25 2961 case ABLS: 2962 return 0x9<<28 | 0x5<<25 2963 case ABGE: 2964 return 0xa<<28 | 0x5<<25 2965 case ABLT: 2966 return 0xb<<28 | 0x5<<25 2967 case ABGT: 2968 return 0xc<<28 | 0x5<<25 2969 case ABLE: 2970 return 0xd<<28 | 0x5<<25 2971 case AB: 2972 return 0xe<<28 | 0x5<<25 2973 } 2974 2975 c.ctxt.Diag("%v: bad bra %v", p, a) 2976 return 0 2977 } 2978 2979 func (c *ctxt5) olr(v int32, b int, r int, sc int) uint32 { 2980 if sc&C_SBIT != 0 { 2981 c.ctxt.Diag(".nil on LDR/STR instruction") 2982 } 2983 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2984 if sc&C_PBIT == 0 { 2985 o |= 1 << 24 2986 } 2987 if sc&C_UBIT == 0 { 2988 o |= 1 << 23 2989 } 2990 if sc&C_WBIT != 0 { 2991 o |= 1 << 21 2992 } 2993 o |= 1<<26 | 1<<20 2994 if v < 0 { 2995 if sc&C_UBIT != 0 { 2996 c.ctxt.Diag(".U on neg offset") 2997 } 2998 v = -v 2999 o ^= 1 << 23 3000 } 3001 3002 if v >= 1<<12 || v < 0 { 3003 c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp) 3004 } 3005 o |= uint32(v) 3006 o |= (uint32(b) & 15) << 16 3007 o |= (uint32(r) & 15) << 12 3008 return o 3009 } 3010 3011 func (c *ctxt5) olhr(v int32, b int, r int, sc int) uint32 { 3012 if sc&C_SBIT != 0 { 3013 c.ctxt.Diag(".nil on LDRH/STRH instruction") 3014 } 3015 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 3016 if sc&C_PBIT == 0 { 3017 o |= 1 << 24 3018 } 3019 if sc&C_WBIT != 0 { 3020 o |= 1 << 21 3021 } 3022 o |= 1<<23 | 1<<20 | 0xb<<4 3023 if v < 0 { 3024 v = -v 3025 o ^= 1 << 23 3026 } 3027 3028 if v >= 1<<8 || v < 0 { 3029 c.ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, c.printp) 3030 } 3031 o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22 3032 o |= (uint32(b) & 15) << 16 3033 o |= (uint32(r) & 15) << 12 3034 return o 3035 } 3036 3037 func (c *ctxt5) osr(a obj.As, r int, v int32, b int, sc int) uint32 { 3038 o := c.olr(v, b, r, sc) ^ (1 << 20) 3039 if a != AMOVW { 3040 o |= 1 << 22 3041 } 3042 return o 3043 } 3044 3045 func (c *ctxt5) oshr(r int, v int32, b int, sc int) uint32 { 3046 o := c.olhr(v, b, r, sc) ^ (1 << 20) 3047 return o 3048 } 3049 3050 func (c *ctxt5) osrr(r int, i int, b int, sc int) uint32 { 3051 return c.olr(int32(i), b, r, sc) ^ (1<<25 | 1<<20) 3052 } 3053 3054 func (c *ctxt5) oshrr(r int, i int, b int, sc int) uint32 { 3055 return c.olhr(int32(i), b, r, sc) ^ (1<<22 | 1<<20) 3056 } 3057 3058 func (c *ctxt5) olrr(i int, b int, r int, sc int) uint32 { 3059 return c.olr(int32(i), b, r, sc) ^ (1 << 25) 3060 } 3061 3062 func (c *ctxt5) olhrr(i int, b int, r int, sc int) uint32 { 3063 return c.olhr(int32(i), b, r, sc) ^ (1 << 22) 3064 } 3065 3066 func (c *ctxt5) ofsr(a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 { 3067 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 3068 if sc&C_PBIT == 0 { 3069 o |= 1 << 24 3070 } 3071 if sc&C_WBIT != 0 { 3072 o |= 1 << 21 3073 } 3074 o |= 6<<25 | 1<<24 | 1<<23 | 10<<8 3075 if v < 0 { 3076 v = -v 3077 o ^= 1 << 23 3078 } 3079 3080 if v&3 != 0 { 3081 c.ctxt.Diag("odd offset for floating point op: %d\n%v", v, p) 3082 } else if v >= 1<<10 || v < 0 { 3083 c.ctxt.Diag("literal span too large: %d\n%v", v, p) 3084 } 3085 o |= (uint32(v) >> 2) & 0xFF 3086 o |= (uint32(b) & 15) << 16 3087 o |= (uint32(r) & 15) << 12 3088 3089 switch a { 3090 default: 3091 c.ctxt.Diag("bad fst %v", a) 3092 fallthrough 3093 3094 case AMOVD: 3095 o |= 1 << 8 3096 fallthrough 3097 3098 case AMOVF: 3099 break 3100 } 3101 3102 return o 3103 } 3104 3105 // MOVW $"lower 16-bit", Reg 3106 func (c *ctxt5) omvs(p *obj.Prog, a *obj.Addr, dr int) uint32 { 3107 var o1 uint32 3108 o1 = ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 3109 o1 |= 0x30 << 20 3110 o1 |= (uint32(dr) & 15) << 12 3111 o1 |= uint32(a.Offset) & 0x0fff 3112 o1 |= (uint32(a.Offset) & 0xf000) << 4 3113 return o1 3114 } 3115 3116 func (c *ctxt5) omvl(p *obj.Prog, a *obj.Addr, dr int) uint32 { 3117 var o1 uint32 3118 if p.Pcond == nil { 3119 c.aclass(a) 3120 v := immrot(^uint32(c.instoffset)) 3121 if v == 0 { 3122 c.ctxt.Diag("%v: missing literal", p) 3123 return 0 3124 } 3125 3126 o1 = c.oprrr(p, AMVN, int(p.Scond)&C_SCOND) 3127 o1 |= uint32(v) 3128 o1 |= (uint32(dr) & 15) << 12 3129 } else { 3130 v := int32(p.Pcond.Pc - p.Pc - 8) 3131 o1 = c.olr(v, REGPC, dr, int(p.Scond)&C_SCOND) 3132 } 3133 3134 return o1 3135 } 3136 3137 func (c *ctxt5) chipzero5(e float64) int { 3138 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 3139 if objabi.GOARM < 7 || e != 0 { 3140 return -1 3141 } 3142 return 0 3143 } 3144 3145 func (c *ctxt5) chipfloat5(e float64) int { 3146 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 3147 if objabi.GOARM < 7 { 3148 return -1 3149 } 3150 3151 ei := math.Float64bits(e) 3152 l := uint32(ei) 3153 h := uint32(ei >> 32) 3154 3155 if l != 0 || h&0xffff != 0 { 3156 return -1 3157 } 3158 h1 := h & 0x7fc00000 3159 if h1 != 0x40000000 && h1 != 0x3fc00000 { 3160 return -1 3161 } 3162 n := 0 3163 3164 // sign bit (a) 3165 if h&0x80000000 != 0 { 3166 n |= 1 << 7 3167 } 3168 3169 // exp sign bit (b) 3170 if h1 == 0x3fc00000 { 3171 n |= 1 << 6 3172 } 3173 3174 // rest of exp and mantissa (cd-efgh) 3175 n |= int((h >> 16) & 0x3f) 3176 3177 //print("match %.8lux %.8lux %d\n", l, h, n); 3178 return n 3179 } 3180 3181 func nocache(p *obj.Prog) { 3182 p.Optab = 0 3183 p.From.Class = 0 3184 if p.From3 != nil { 3185 p.From3.Class = 0 3186 } 3187 p.To.Class = 0 3188 }