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