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