github.com/jonasi/go@v0.0.0-20150930005915-e78e654c1de0/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 if ctxt.Tlsg == nil { 743 ctxt.Tlsg = obj.Linklookup(ctxt, "runtime.tlsg", 0) 744 } 745 746 p = cursym.Text 747 ctxt.Autosize = int32(p.To.Offset + 4) 748 obj.Symgrow(ctxt, cursym, cursym.Size) 749 750 bp := cursym.P 751 c = int32(p.Pc) // even p->link might need extra padding 752 var v int 753 for p = p.Link; p != nil; p = p.Link { 754 ctxt.Pc = p.Pc 755 ctxt.Curp = p 756 o = oplook(ctxt, p) 757 opc = int32(p.Pc) 758 if ctxt.Headtype != obj.Hnacl { 759 asmout(ctxt, p, o, out[:]) 760 m = int(o.size) 761 } else { 762 m = asmoutnacl(ctxt, c, p, o, out[:]) 763 if int64(opc) != p.Pc { 764 ctxt.Diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %v", opc, int32(p.Pc), p) 765 } 766 } 767 768 if m%4 != 0 || p.Pc%4 != 0 { 769 ctxt.Diag("final stage: pc invalid: %v size=%d", p, m) 770 } 771 772 if int64(c) > p.Pc { 773 ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, c, p) 774 } 775 for int64(c) != p.Pc { 776 // emit 0xe1a00000 (MOVW R0, R0) 777 bp[0] = 0x00 778 bp = bp[1:] 779 780 bp[0] = 0x00 781 bp = bp[1:] 782 bp[0] = 0xa0 783 bp = bp[1:] 784 bp[0] = 0xe1 785 bp = bp[1:] 786 c += 4 787 } 788 789 for i = 0; i < m/4; i++ { 790 v = int(out[i]) 791 bp[0] = byte(v) 792 bp = bp[1:] 793 bp[0] = byte(v >> 8) 794 bp = bp[1:] 795 bp[0] = byte(v >> 16) 796 bp = bp[1:] 797 bp[0] = byte(v >> 24) 798 bp = bp[1:] 799 } 800 801 c += int32(m) 802 } 803 } 804 805 /* 806 * when the first reference to the literal pool threatens 807 * to go out of range of a 12-bit PC-relative offset, 808 * drop the pool now, and branch round it. 809 * this happens only in extended basic blocks that exceed 4k. 810 */ 811 func checkpool(ctxt *obj.Link, p *obj.Prog, sz int) bool { 812 if pool.size >= 0xff0 || immaddr(int32((p.Pc+int64(sz)+4)+4+int64(12+pool.size)-int64(pool.start+8))) == 0 { 813 return flushpool(ctxt, p, 1, 0) 814 } else if p.Link == nil { 815 return flushpool(ctxt, p, 2, 0) 816 } 817 return false 818 } 819 820 func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool { 821 if ctxt.Blitrl != nil { 822 if skip != 0 { 823 if false && skip == 1 { 824 fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start) 825 } 826 q := ctxt.NewProg() 827 q.As = AB 828 q.To.Type = obj.TYPE_BRANCH 829 q.Pcond = p.Link 830 q.Link = ctxt.Blitrl 831 q.Lineno = p.Lineno 832 ctxt.Blitrl = q 833 } 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 834 return false 835 } 836 if ctxt.Headtype == obj.Hnacl && pool.size%16 != 0 { 837 // if pool is not multiple of 16 bytes, add an alignment marker 838 q := ctxt.NewProg() 839 840 q.As = ADATABUNDLEEND 841 ctxt.Elitrl.Link = q 842 ctxt.Elitrl = q 843 } 844 845 // The line number for constant pool entries doesn't really matter. 846 // We set it to the line number of the preceding instruction so that 847 // there are no deltas to encode in the pc-line tables. 848 for q := ctxt.Blitrl; q != nil; q = q.Link { 849 q.Lineno = p.Lineno 850 } 851 852 ctxt.Elitrl.Link = p.Link 853 p.Link = ctxt.Blitrl 854 855 ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */ 856 ctxt.Elitrl = nil 857 pool.size = 0 858 pool.start = 0 859 pool.extra = 0 860 return true 861 } 862 863 return false 864 } 865 866 func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { 867 var t obj.Prog 868 869 c := aclass(ctxt, a) 870 871 t.Ctxt = ctxt 872 t.As = AWORD 873 874 switch c { 875 default: 876 t.To.Offset = a.Offset 877 t.To.Sym = a.Sym 878 t.To.Type = a.Type 879 t.To.Name = a.Name 880 881 if ctxt.Flag_shared != 0 && t.To.Sym != nil { 882 t.Rel = p 883 } 884 885 case C_SROREG, 886 C_LOREG, 887 C_ROREG, 888 C_FOREG, 889 C_SOREG, 890 C_HOREG, 891 C_FAUTO, 892 C_SAUTO, 893 C_LAUTO, 894 C_LACON: 895 t.To.Type = obj.TYPE_CONST 896 t.To.Offset = ctxt.Instoffset 897 } 898 899 if t.Rel == nil { 900 for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */ 901 if q.Rel == nil && q.To == t.To { 902 p.Pcond = q 903 return 904 } 905 } 906 } 907 908 if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 { 909 // start a new data bundle 910 q := ctxt.NewProg() 911 q.As = ADATABUNDLE 912 q.Pc = int64(pool.size) 913 pool.size += 4 914 if ctxt.Blitrl == nil { 915 ctxt.Blitrl = q 916 pool.start = uint32(p.Pc) 917 } else { 918 ctxt.Elitrl.Link = q 919 } 920 921 ctxt.Elitrl = q 922 } 923 924 q := ctxt.NewProg() 925 *q = t 926 q.Pc = int64(pool.size) 927 928 if ctxt.Blitrl == nil { 929 ctxt.Blitrl = q 930 pool.start = uint32(p.Pc) 931 } else { 932 ctxt.Elitrl.Link = q 933 } 934 ctxt.Elitrl = q 935 pool.size += 4 936 937 p.Pcond = q 938 } 939 940 func regoff(ctxt *obj.Link, a *obj.Addr) int32 { 941 ctxt.Instoffset = 0 942 aclass(ctxt, a) 943 return int32(ctxt.Instoffset) 944 } 945 946 func immrot(v uint32) int32 { 947 for i := 0; i < 16; i++ { 948 if v&^0xff == 0 { 949 return int32(uint32(int32(i)<<8) | v | 1<<25) 950 } 951 v = v<<2 | v>>30 952 } 953 954 return 0 955 } 956 957 func immaddr(v int32) int32 { 958 if v >= 0 && v <= 0xfff { 959 return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */ 960 } 961 if v >= -0xfff && v < 0 { 962 return -v&0xfff | 1<<24 /* pre indexing */ 963 } 964 return 0 965 } 966 967 func immfloat(v int32) bool { 968 return v&0xC03 == 0 /* offset will fit in floating-point load/store */ 969 } 970 971 func immhalf(v int32) bool { 972 if v >= 0 && v <= 0xff { 973 return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */ 974 } 975 if v >= -0xff && v < 0 { 976 return -v&0xff|1<<24 != 0 /* pre indexing */ 977 } 978 return false 979 } 980 981 func aclass(ctxt *obj.Link, a *obj.Addr) int { 982 switch a.Type { 983 case obj.TYPE_NONE: 984 return C_NONE 985 986 case obj.TYPE_REG: 987 if REG_R0 <= a.Reg && a.Reg <= REG_R15 { 988 return C_REG 989 } 990 if REG_F0 <= a.Reg && a.Reg <= REG_F15 { 991 return C_FREG 992 } 993 if a.Reg == REG_FPSR || a.Reg == REG_FPCR { 994 return C_FCR 995 } 996 if a.Reg == REG_CPSR || a.Reg == REG_SPSR { 997 return C_PSR 998 } 999 return C_GOK 1000 1001 case obj.TYPE_REGREG: 1002 return C_REGREG 1003 1004 case obj.TYPE_REGREG2: 1005 return C_REGREG2 1006 1007 case obj.TYPE_REGLIST: 1008 return C_REGLIST 1009 1010 case obj.TYPE_SHIFT: 1011 return C_SHIFT 1012 1013 case obj.TYPE_MEM: 1014 switch a.Name { 1015 case obj.NAME_EXTERN, 1016 obj.NAME_STATIC: 1017 if a.Sym == nil || a.Sym.Name == "" { 1018 fmt.Printf("null sym external\n") 1019 return C_GOK 1020 } 1021 1022 ctxt.Instoffset = 0 // s.b. unused but just in case 1023 if a.Sym.Type == obj.STLSBSS { 1024 if ctxt.Flag_shared != 0 { 1025 return C_TLS_IE 1026 } else { 1027 return C_TLS_LE 1028 } 1029 } 1030 1031 return C_ADDR 1032 1033 case obj.NAME_AUTO: 1034 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset 1035 t := int(immaddr(int32(ctxt.Instoffset))) 1036 if t != 0 { 1037 if immhalf(int32(ctxt.Instoffset)) { 1038 if immfloat(int32(t)) { 1039 return C_HFAUTO 1040 } 1041 return C_HAUTO 1042 } 1043 1044 if immfloat(int32(t)) { 1045 return C_FAUTO 1046 } 1047 return C_SAUTO 1048 } 1049 1050 return C_LAUTO 1051 1052 case obj.NAME_PARAM: 1053 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4 1054 t := int(immaddr(int32(ctxt.Instoffset))) 1055 if t != 0 { 1056 if immhalf(int32(ctxt.Instoffset)) { 1057 if immfloat(int32(t)) { 1058 return C_HFAUTO 1059 } 1060 return C_HAUTO 1061 } 1062 1063 if immfloat(int32(t)) { 1064 return C_FAUTO 1065 } 1066 return C_SAUTO 1067 } 1068 1069 return C_LAUTO 1070 1071 case obj.TYPE_NONE: 1072 ctxt.Instoffset = a.Offset 1073 t := int(immaddr(int32(ctxt.Instoffset))) 1074 if t != 0 { 1075 if immhalf(int32(ctxt.Instoffset)) { /* n.b. that it will also satisfy immrot */ 1076 if immfloat(int32(t)) { 1077 return C_HFOREG 1078 } 1079 return C_HOREG 1080 } 1081 1082 if immfloat(int32(t)) { 1083 return C_FOREG /* n.b. that it will also satisfy immrot */ 1084 } 1085 t := int(immrot(uint32(ctxt.Instoffset))) 1086 if t != 0 { 1087 return C_SROREG 1088 } 1089 if immhalf(int32(ctxt.Instoffset)) { 1090 return C_HOREG 1091 } 1092 return C_SOREG 1093 } 1094 1095 t = int(immrot(uint32(ctxt.Instoffset))) 1096 if t != 0 { 1097 return C_ROREG 1098 } 1099 return C_LOREG 1100 } 1101 1102 return C_GOK 1103 1104 case obj.TYPE_FCONST: 1105 if chipzero5(ctxt, a.Val.(float64)) >= 0 { 1106 return C_ZFCON 1107 } 1108 if chipfloat5(ctxt, a.Val.(float64)) >= 0 { 1109 return C_SFCON 1110 } 1111 return C_LFCON 1112 1113 case obj.TYPE_TEXTSIZE: 1114 return C_TEXTSIZE 1115 1116 case obj.TYPE_CONST, 1117 obj.TYPE_ADDR: 1118 switch a.Name { 1119 case obj.TYPE_NONE: 1120 ctxt.Instoffset = a.Offset 1121 if a.Reg != 0 { 1122 return aconsize(ctxt) 1123 } 1124 1125 t := int(immrot(uint32(ctxt.Instoffset))) 1126 if t != 0 { 1127 return C_RCON 1128 } 1129 t = int(immrot(^uint32(ctxt.Instoffset))) 1130 if t != 0 { 1131 return C_NCON 1132 } 1133 return C_LCON 1134 1135 case obj.NAME_EXTERN, 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) where offset != 0", p) 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 // runtime.tlsg is special. 1650 // Its "address" is the offset from the TLS thread pointer 1651 // to the thread-local g and m pointers. 1652 // Emit a TLS relocation instead of a standard one if its 1653 // type is not explicitly set by runtime. This assumes that 1654 // all references to runtime.tlsg should be accompanied with 1655 // its type declaration if necessary. 1656 if rel.Sym == ctxt.Tlsg && ctxt.Tlsg.Type == 0 { 1657 rel.Type = obj.R_TLS 1658 if ctxt.Flag_shared != 0 { 1659 rel.Add += ctxt.Pc - p.Rel.Pc - 8 - int64(rel.Siz) 1660 } 1661 } else if ctxt.Flag_shared != 0 { 1662 rel.Type = obj.R_PCREL 1663 rel.Add += ctxt.Pc - p.Rel.Pc - 8 1664 } else { 1665 rel.Type = obj.R_ADDR 1666 } 1667 o1 = 0 1668 } 1669 1670 case 12: /* movw $lcon, reg */ 1671 o1 = omvl(ctxt, p, &p.From, int(p.To.Reg)) 1672 1673 if o.flag&LPCREL != 0 { 1674 o2 = oprrr(ctxt, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12 1675 } 1676 1677 case 13: /* op $lcon, [R], R */ 1678 o1 = omvl(ctxt, p, &p.From, REGTMP) 1679 1680 if o1 == 0 { 1681 break 1682 } 1683 o2 = oprrr(ctxt, int(p.As), int(p.Scond)) 1684 o2 |= REGTMP & 15 1685 r := int(p.Reg) 1686 if p.As == AMOVW || p.As == AMVN { 1687 r = 0 1688 } else if r == 0 { 1689 r = int(p.To.Reg) 1690 } 1691 o2 |= (uint32(r) & 15) << 16 1692 if p.To.Type != obj.TYPE_NONE { 1693 o2 |= (uint32(p.To.Reg) & 15) << 12 1694 } 1695 1696 case 14: /* movb/movbu/movh/movhu R,R */ 1697 o1 = oprrr(ctxt, ASLL, int(p.Scond)) 1698 1699 if p.As == AMOVBU || p.As == AMOVHU { 1700 o2 = oprrr(ctxt, ASRL, int(p.Scond)) 1701 } else { 1702 o2 = oprrr(ctxt, ASRA, int(p.Scond)) 1703 } 1704 1705 r := int(p.To.Reg) 1706 o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12 1707 o2 |= uint32(r)&15 | (uint32(r)&15)<<12 1708 if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU { 1709 o1 |= 24 << 7 1710 o2 |= 24 << 7 1711 } else { 1712 o1 |= 16 << 7 1713 o2 |= 16 << 7 1714 } 1715 1716 case 15: /* mul r,[r,]r */ 1717 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 1718 1719 rf := int(p.From.Reg) 1720 rt := int(p.To.Reg) 1721 r := int(p.Reg) 1722 if r == 0 { 1723 r = rt 1724 } 1725 if rt == r { 1726 r = rf 1727 rf = rt 1728 } 1729 1730 if false { 1731 if rt == r || rf == REGPC&15 || r == REGPC&15 || rt == REGPC&15 { 1732 ctxt.Diag("bad registers in MUL") 1733 prasm(p) 1734 } 1735 } 1736 1737 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 1738 1739 case 16: /* div r,[r,]r */ 1740 o1 = 0xf << 28 1741 1742 o2 = 0 1743 1744 case 17: 1745 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 1746 rf := int(p.From.Reg) 1747 rt := int(p.To.Reg) 1748 rt2 := int(p.To.Offset) 1749 r := int(p.Reg) 1750 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12 1751 1752 case 20: /* mov/movb/movbu R,O(R) */ 1753 aclass(ctxt, &p.To) 1754 1755 r := int(p.To.Reg) 1756 if r == 0 { 1757 r = int(o.param) 1758 } 1759 o1 = osr(ctxt, int(p.As), int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond)) 1760 1761 case 21: /* mov/movbu O(R),R -> lr */ 1762 aclass(ctxt, &p.From) 1763 1764 r := int(p.From.Reg) 1765 if r == 0 { 1766 r = int(o.param) 1767 } 1768 o1 = olr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond)) 1769 if p.As != AMOVW { 1770 o1 |= 1 << 22 1771 } 1772 1773 case 30: /* mov/movb/movbu R,L(R) */ 1774 o1 = omvl(ctxt, p, &p.To, REGTMP) 1775 1776 if o1 == 0 { 1777 break 1778 } 1779 r := int(p.To.Reg) 1780 if r == 0 { 1781 r = int(o.param) 1782 } 1783 o2 = osrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond)) 1784 if p.As != AMOVW { 1785 o2 |= 1 << 22 1786 } 1787 1788 case 31: /* mov/movbu L(R),R -> lr[b] */ 1789 o1 = omvl(ctxt, p, &p.From, REGTMP) 1790 1791 if o1 == 0 { 1792 break 1793 } 1794 r := int(p.From.Reg) 1795 if r == 0 { 1796 r = int(o.param) 1797 } 1798 o2 = olrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond)) 1799 if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { 1800 o2 |= 1 << 22 1801 } 1802 1803 case 34: /* mov $lacon,R */ 1804 o1 = omvl(ctxt, p, &p.From, REGTMP) 1805 1806 if o1 == 0 { 1807 break 1808 } 1809 1810 o2 = oprrr(ctxt, AADD, int(p.Scond)) 1811 o2 |= REGTMP & 15 1812 r := int(p.From.Reg) 1813 if r == 0 { 1814 r = int(o.param) 1815 } 1816 o2 |= (uint32(r) & 15) << 16 1817 if p.To.Type != obj.TYPE_NONE { 1818 o2 |= (uint32(p.To.Reg) & 15) << 12 1819 } 1820 1821 case 35: /* mov PSR,R */ 1822 o1 = 2<<23 | 0xf<<16 | 0<<0 1823 1824 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1825 o1 |= (uint32(p.From.Reg) & 1) << 22 1826 o1 |= (uint32(p.To.Reg) & 15) << 12 1827 1828 case 36: /* mov R,PSR */ 1829 o1 = 2<<23 | 0x29f<<12 | 0<<4 1830 1831 if p.Scond&C_FBIT != 0 { 1832 o1 ^= 0x010 << 12 1833 } 1834 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1835 o1 |= (uint32(p.To.Reg) & 1) << 22 1836 o1 |= (uint32(p.From.Reg) & 15) << 0 1837 1838 case 37: /* mov $con,PSR */ 1839 aclass(ctxt, &p.From) 1840 1841 o1 = 2<<23 | 0x29f<<12 | 0<<4 1842 if p.Scond&C_FBIT != 0 { 1843 o1 ^= 0x010 << 12 1844 } 1845 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1846 o1 |= uint32(immrot(uint32(ctxt.Instoffset))) 1847 o1 |= (uint32(p.To.Reg) & 1) << 22 1848 o1 |= (uint32(p.From.Reg) & 15) << 0 1849 1850 case 38, 39: 1851 switch o.type_ { 1852 case 38: /* movm $con,oreg -> stm */ 1853 o1 = 0x4 << 25 1854 1855 o1 |= uint32(p.From.Offset & 0xffff) 1856 o1 |= (uint32(p.To.Reg) & 15) << 16 1857 aclass(ctxt, &p.To) 1858 1859 case 39: /* movm oreg,$con -> ldm */ 1860 o1 = 0x4<<25 | 1<<20 1861 1862 o1 |= uint32(p.To.Offset & 0xffff) 1863 o1 |= (uint32(p.From.Reg) & 15) << 16 1864 aclass(ctxt, &p.From) 1865 } 1866 1867 if ctxt.Instoffset != 0 { 1868 ctxt.Diag("offset must be zero in MOVM; %v", p) 1869 } 1870 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1871 if p.Scond&C_PBIT != 0 { 1872 o1 |= 1 << 24 1873 } 1874 if p.Scond&C_UBIT != 0 { 1875 o1 |= 1 << 23 1876 } 1877 if p.Scond&C_SBIT != 0 { 1878 o1 |= 1 << 22 1879 } 1880 if p.Scond&C_WBIT != 0 { 1881 o1 |= 1 << 21 1882 } 1883 1884 case 40: /* swp oreg,reg,reg */ 1885 aclass(ctxt, &p.From) 1886 1887 if ctxt.Instoffset != 0 { 1888 ctxt.Diag("offset must be zero in SWP") 1889 } 1890 o1 = 0x2<<23 | 0x9<<4 1891 if p.As != ASWPW { 1892 o1 |= 1 << 22 1893 } 1894 o1 |= (uint32(p.From.Reg) & 15) << 16 1895 o1 |= (uint32(p.Reg) & 15) << 0 1896 o1 |= (uint32(p.To.Reg) & 15) << 12 1897 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1898 1899 case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ 1900 o1 = 0xe8fd8000 1901 1902 case 50: /* floating point store */ 1903 v := regoff(ctxt, &p.To) 1904 1905 r := int(p.To.Reg) 1906 if r == 0 { 1907 r = int(o.param) 1908 } 1909 o1 = ofsr(ctxt, int(p.As), int(p.From.Reg), v, r, int(p.Scond), p) 1910 1911 case 51: /* floating point load */ 1912 v := regoff(ctxt, &p.From) 1913 1914 r := int(p.From.Reg) 1915 if r == 0 { 1916 r = int(o.param) 1917 } 1918 o1 = ofsr(ctxt, int(p.As), int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20 1919 1920 case 52: /* floating point store, int32 offset UGLY */ 1921 o1 = omvl(ctxt, p, &p.To, REGTMP) 1922 1923 if o1 == 0 { 1924 break 1925 } 1926 r := int(p.To.Reg) 1927 if r == 0 { 1928 r = int(o.param) 1929 } 1930 o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 1931 o3 = ofsr(ctxt, int(p.As), int(p.From.Reg), 0, REGTMP, int(p.Scond), p) 1932 1933 case 53: /* floating point load, int32 offset UGLY */ 1934 o1 = omvl(ctxt, p, &p.From, REGTMP) 1935 1936 if o1 == 0 { 1937 break 1938 } 1939 r := int(p.From.Reg) 1940 if r == 0 { 1941 r = int(o.param) 1942 } 1943 o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 1944 o3 = ofsr(ctxt, int(p.As), int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 1945 1946 case 54: /* floating point arith */ 1947 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 1948 1949 rf := int(p.From.Reg) 1950 rt := int(p.To.Reg) 1951 r := int(p.Reg) 1952 if r == 0 { 1953 r = rt 1954 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 { 1955 r = 0 1956 } 1957 } 1958 1959 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1960 1961 case 56: /* move to FP[CS]R */ 1962 o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4 1963 1964 o1 |= ((uint32(p.To.Reg)&1)+1)<<21 | (uint32(p.From.Reg)&15)<<12 1965 1966 case 57: /* move from FP[CS]R */ 1967 o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4 1968 1969 o1 |= ((uint32(p.From.Reg)&1)+1)<<21 | (uint32(p.To.Reg)&15)<<12 | 1<<20 1970 1971 case 58: /* movbu R,R */ 1972 o1 = oprrr(ctxt, AAND, int(p.Scond)) 1973 1974 o1 |= uint32(immrot(0xff)) 1975 rt := int(p.To.Reg) 1976 r := int(p.From.Reg) 1977 if p.To.Type == obj.TYPE_NONE { 1978 rt = 0 1979 } 1980 if r == 0 { 1981 r = rt 1982 } 1983 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1984 1985 case 59: /* movw/bu R<<I(R),R -> ldr indexed */ 1986 if p.From.Reg == 0 { 1987 if p.As != AMOVW { 1988 ctxt.Diag("byte MOV from shifter operand") 1989 } 1990 o1 = mov(ctxt, p) 1991 break 1992 } 1993 1994 if p.From.Offset&(1<<4) != 0 { 1995 ctxt.Diag("bad shift in LDR") 1996 } 1997 o1 = olrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) 1998 if p.As == AMOVBU { 1999 o1 |= 1 << 22 2000 } 2001 2002 case 60: /* movb R(R),R -> ldrsb indexed */ 2003 if p.From.Reg == 0 { 2004 ctxt.Diag("byte MOV from shifter operand") 2005 o1 = mov(ctxt, p) 2006 break 2007 } 2008 2009 if p.From.Offset&(^0xf) != 0 { 2010 ctxt.Diag("bad shift in LDRSB") 2011 } 2012 o1 = olhrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) 2013 o1 ^= 1<<5 | 1<<6 2014 2015 case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ 2016 if p.To.Reg == 0 { 2017 ctxt.Diag("MOV to shifter operand") 2018 } 2019 o1 = osrr(ctxt, int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond)) 2020 if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU { 2021 o1 |= 1 << 22 2022 } 2023 2024 /* reloc ops */ 2025 case 64: /* mov/movb/movbu R,addr */ 2026 o1 = omvl(ctxt, p, &p.To, REGTMP) 2027 2028 if o1 == 0 { 2029 break 2030 } 2031 o2 = osr(ctxt, int(p.As), int(p.From.Reg), 0, REGTMP, int(p.Scond)) 2032 if o.flag&LPCREL != 0 { 2033 o3 = o2 2034 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2035 } 2036 2037 case 65: /* mov/movbu addr,R */ 2038 o1 = omvl(ctxt, p, &p.From, REGTMP) 2039 2040 if o1 == 0 { 2041 break 2042 } 2043 o2 = olr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond)) 2044 if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { 2045 o2 |= 1 << 22 2046 } 2047 if o.flag&LPCREL != 0 { 2048 o3 = o2 2049 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2050 } 2051 2052 case 101: /* movw tlsvar,R, local exec*/ 2053 if p.Scond&C_SCOND != C_SCOND_NONE { 2054 ctxt.Diag("conditional tls") 2055 } 2056 o1 = omvl(ctxt, p, &p.From, int(p.To.Reg)) 2057 2058 case 102: /* movw tlsvar,R, initial exec*/ 2059 if p.Scond&C_SCOND != C_SCOND_NONE { 2060 ctxt.Diag("conditional tls") 2061 } 2062 o1 = omvl(ctxt, p, &p.From, int(p.To.Reg)) 2063 o2 = olrr(ctxt, int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond)) 2064 2065 case 103: /* word tlsvar, local exec */ 2066 if p.To.Sym == nil { 2067 ctxt.Diag("nil sym in tls %v", p) 2068 } 2069 if p.To.Offset != 0 { 2070 ctxt.Diag("offset against tls var in %v", p) 2071 } 2072 // This case happens with words generated in the PC stream as part of 2073 // the literal pool. 2074 rel := obj.Addrel(ctxt.Cursym) 2075 2076 rel.Off = int32(ctxt.Pc) 2077 rel.Siz = 4 2078 rel.Sym = p.To.Sym 2079 rel.Type = obj.R_TLS_LE 2080 o1 = 0 2081 2082 case 104: /* word tlsvar, initial exec */ 2083 if p.To.Sym == nil { 2084 ctxt.Diag("nil sym in tls %v", p) 2085 } 2086 if p.To.Offset != 0 { 2087 ctxt.Diag("offset against tls var in %v", p) 2088 } 2089 rel := obj.Addrel(ctxt.Cursym) 2090 rel.Off = int32(ctxt.Pc) 2091 rel.Siz = 4 2092 rel.Sym = p.To.Sym 2093 rel.Type = obj.R_TLS_IE 2094 rel.Add = ctxt.Pc - p.Rel.Pc - 8 - int64(rel.Siz) 2095 2096 case 68: /* floating point store -> ADDR */ 2097 o1 = omvl(ctxt, p, &p.To, REGTMP) 2098 2099 if o1 == 0 { 2100 break 2101 } 2102 o2 = ofsr(ctxt, int(p.As), int(p.From.Reg), 0, REGTMP, int(p.Scond), p) 2103 if o.flag&LPCREL != 0 { 2104 o3 = o2 2105 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2106 } 2107 2108 case 69: /* floating point load <- ADDR */ 2109 o1 = omvl(ctxt, p, &p.From, REGTMP) 2110 2111 if o1 == 0 { 2112 break 2113 } 2114 o2 = ofsr(ctxt, int(p.As), int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 2115 if o.flag&LPCREL != 0 { 2116 o3 = o2 2117 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2118 } 2119 2120 /* ArmV4 ops: */ 2121 case 70: /* movh/movhu R,O(R) -> strh */ 2122 aclass(ctxt, &p.To) 2123 2124 r := int(p.To.Reg) 2125 if r == 0 { 2126 r = int(o.param) 2127 } 2128 o1 = oshr(ctxt, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond)) 2129 2130 case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ 2131 aclass(ctxt, &p.From) 2132 2133 r := int(p.From.Reg) 2134 if r == 0 { 2135 r = int(o.param) 2136 } 2137 o1 = olhr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond)) 2138 if p.As == AMOVB || p.As == AMOVBS { 2139 o1 ^= 1<<5 | 1<<6 2140 } else if p.As == AMOVH || p.As == AMOVHS { 2141 o1 ^= (1 << 6) 2142 } 2143 2144 case 72: /* movh/movhu R,L(R) -> strh */ 2145 o1 = omvl(ctxt, p, &p.To, REGTMP) 2146 2147 if o1 == 0 { 2148 break 2149 } 2150 r := int(p.To.Reg) 2151 if r == 0 { 2152 r = int(o.param) 2153 } 2154 o2 = oshrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond)) 2155 2156 case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ 2157 o1 = omvl(ctxt, p, &p.From, REGTMP) 2158 2159 if o1 == 0 { 2160 break 2161 } 2162 r := int(p.From.Reg) 2163 if r == 0 { 2164 r = int(o.param) 2165 } 2166 o2 = olhrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond)) 2167 if p.As == AMOVB || p.As == AMOVBS { 2168 o2 ^= 1<<5 | 1<<6 2169 } else if p.As == AMOVH || p.As == AMOVHS { 2170 o2 ^= (1 << 6) 2171 } 2172 2173 case 74: /* bx $I */ 2174 ctxt.Diag("ABX $I") 2175 2176 case 75: /* bx O(R) */ 2177 aclass(ctxt, &p.To) 2178 2179 if ctxt.Instoffset != 0 { 2180 ctxt.Diag("non-zero offset in ABX") 2181 } 2182 2183 /* 2184 o1 = oprrr(ctxt, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR 2185 o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0); // BX R 2186 */ 2187 // p->to.reg may be REGLINK 2188 o1 = oprrr(ctxt, AADD, int(p.Scond)) 2189 2190 o1 |= uint32(immrot(uint32(ctxt.Instoffset))) 2191 o1 |= (uint32(p.To.Reg) & 15) << 16 2192 o1 |= (REGTMP & 15) << 12 2193 o2 = oprrr(ctxt, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR 2194 o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15 // BX Rtmp 2195 2196 case 76: /* bx O(R) when returning from fn*/ 2197 ctxt.Diag("ABXRET") 2198 2199 case 77: /* ldrex oreg,reg */ 2200 aclass(ctxt, &p.From) 2201 2202 if ctxt.Instoffset != 0 { 2203 ctxt.Diag("offset must be zero in LDREX") 2204 } 2205 o1 = 0x19<<20 | 0xf9f 2206 o1 |= (uint32(p.From.Reg) & 15) << 16 2207 o1 |= (uint32(p.To.Reg) & 15) << 12 2208 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2209 2210 case 78: /* strex reg,oreg,reg */ 2211 aclass(ctxt, &p.From) 2212 2213 if ctxt.Instoffset != 0 { 2214 ctxt.Diag("offset must be zero in STREX") 2215 } 2216 o1 = 0x18<<20 | 0xf90 2217 o1 |= (uint32(p.From.Reg) & 15) << 16 2218 o1 |= (uint32(p.Reg) & 15) << 0 2219 o1 |= (uint32(p.To.Reg) & 15) << 12 2220 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2221 2222 case 80: /* fmov zfcon,freg */ 2223 if p.As == AMOVD { 2224 o1 = 0xeeb00b00 // VMOV imm 64 2225 o2 = oprrr(ctxt, ASUBD, int(p.Scond)) 2226 } else { 2227 o1 = 0x0eb00a00 // VMOV imm 32 2228 o2 = oprrr(ctxt, ASUBF, int(p.Scond)) 2229 } 2230 2231 v := int32(0x70) // 1.0 2232 r := (int(p.To.Reg) & 15) << 0 2233 2234 // movf $1.0, r 2235 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2236 2237 o1 |= (uint32(r) & 15) << 12 2238 o1 |= (uint32(v) & 0xf) << 0 2239 o1 |= (uint32(v) & 0xf0) << 12 2240 2241 // subf r,r,r 2242 o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12 2243 2244 case 81: /* fmov sfcon,freg */ 2245 o1 = 0x0eb00a00 // VMOV imm 32 2246 if p.As == AMOVD { 2247 o1 = 0xeeb00b00 // VMOV imm 64 2248 } 2249 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2250 o1 |= (uint32(p.To.Reg) & 15) << 12 2251 v := int32(chipfloat5(ctxt, p.From.Val.(float64))) 2252 o1 |= (uint32(v) & 0xf) << 0 2253 o1 |= (uint32(v) & 0xf0) << 12 2254 2255 case 82: /* fcmp freg,freg, */ 2256 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2257 2258 o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0 2259 o2 = 0x0ef1fa10 // VMRS R15 2260 o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2261 2262 case 83: /* fcmp freg,, */ 2263 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2264 2265 o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16 2266 o2 = 0x0ef1fa10 // VMRS R15 2267 o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2268 2269 case 84: /* movfw freg,freg - truncate float-to-fix */ 2270 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2271 2272 o1 |= (uint32(p.From.Reg) & 15) << 0 2273 o1 |= (uint32(p.To.Reg) & 15) << 12 2274 2275 case 85: /* movwf freg,freg - fix-to-float */ 2276 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2277 2278 o1 |= (uint32(p.From.Reg) & 15) << 0 2279 o1 |= (uint32(p.To.Reg) & 15) << 12 2280 2281 // macro for movfw freg,FTMP; movw FTMP,reg 2282 case 86: /* movfw freg,reg - truncate float-to-fix */ 2283 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2284 2285 o1 |= (uint32(p.From.Reg) & 15) << 0 2286 o1 |= (FREGTMP & 15) << 12 2287 o2 = oprrr(ctxt, AMOVFW+ALAST, int(p.Scond)) 2288 o2 |= (FREGTMP & 15) << 16 2289 o2 |= (uint32(p.To.Reg) & 15) << 12 2290 2291 // macro for movw reg,FTMP; movwf FTMP,freg 2292 case 87: /* movwf reg,freg - fix-to-float */ 2293 o1 = oprrr(ctxt, AMOVWF+ALAST, int(p.Scond)) 2294 2295 o1 |= (uint32(p.From.Reg) & 15) << 12 2296 o1 |= (FREGTMP & 15) << 16 2297 o2 = oprrr(ctxt, int(p.As), int(p.Scond)) 2298 o2 |= (FREGTMP & 15) << 0 2299 o2 |= (uint32(p.To.Reg) & 15) << 12 2300 2301 case 88: /* movw reg,freg */ 2302 o1 = oprrr(ctxt, AMOVWF+ALAST, int(p.Scond)) 2303 2304 o1 |= (uint32(p.From.Reg) & 15) << 12 2305 o1 |= (uint32(p.To.Reg) & 15) << 16 2306 2307 case 89: /* movw freg,reg */ 2308 o1 = oprrr(ctxt, AMOVFW+ALAST, int(p.Scond)) 2309 2310 o1 |= (uint32(p.From.Reg) & 15) << 16 2311 o1 |= (uint32(p.To.Reg) & 15) << 12 2312 2313 case 90: /* tst reg */ 2314 o1 = oprrr(ctxt, ACMP+ALAST, int(p.Scond)) 2315 2316 o1 |= (uint32(p.From.Reg) & 15) << 16 2317 2318 case 91: /* ldrexd oreg,reg */ 2319 aclass(ctxt, &p.From) 2320 2321 if ctxt.Instoffset != 0 { 2322 ctxt.Diag("offset must be zero in LDREX") 2323 } 2324 o1 = 0x1b<<20 | 0xf9f 2325 o1 |= (uint32(p.From.Reg) & 15) << 16 2326 o1 |= (uint32(p.To.Reg) & 15) << 12 2327 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2328 2329 case 92: /* strexd reg,oreg,reg */ 2330 aclass(ctxt, &p.From) 2331 2332 if ctxt.Instoffset != 0 { 2333 ctxt.Diag("offset must be zero in STREX") 2334 } 2335 o1 = 0x1a<<20 | 0xf90 2336 o1 |= (uint32(p.From.Reg) & 15) << 16 2337 o1 |= (uint32(p.Reg) & 15) << 0 2338 o1 |= (uint32(p.To.Reg) & 15) << 12 2339 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2340 2341 case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ 2342 o1 = omvl(ctxt, p, &p.From, REGTMP) 2343 2344 if o1 == 0 { 2345 break 2346 } 2347 o2 = olhr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond)) 2348 if p.As == AMOVB || p.As == AMOVBS { 2349 o2 ^= 1<<5 | 1<<6 2350 } else if p.As == AMOVH || p.As == AMOVHS { 2351 o2 ^= (1 << 6) 2352 } 2353 if o.flag&LPCREL != 0 { 2354 o3 = o2 2355 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2356 } 2357 2358 case 94: /* movh/movhu R,addr -> strh */ 2359 o1 = omvl(ctxt, p, &p.To, REGTMP) 2360 2361 if o1 == 0 { 2362 break 2363 } 2364 o2 = oshr(ctxt, int(p.From.Reg), 0, REGTMP, int(p.Scond)) 2365 if o.flag&LPCREL != 0 { 2366 o3 = o2 2367 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2368 } 2369 2370 case 95: /* PLD off(reg) */ 2371 o1 = 0xf5d0f000 2372 2373 o1 |= (uint32(p.From.Reg) & 15) << 16 2374 if p.From.Offset < 0 { 2375 o1 &^= (1 << 23) 2376 o1 |= uint32((-p.From.Offset) & 0xfff) 2377 } else { 2378 o1 |= uint32(p.From.Offset & 0xfff) 2379 } 2380 2381 // This is supposed to be something that stops execution. 2382 // It's not supposed to be reached, ever, but if it is, we'd 2383 // like to be able to tell how we got there. Assemble as 2384 // 0xf7fabcfd which is guaranteed to raise undefined instruction 2385 // exception. 2386 case 96: /* UNDEF */ 2387 o1 = 0xf7fabcfd 2388 2389 case 97: /* CLZ Rm, Rd */ 2390 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2391 2392 o1 |= (uint32(p.To.Reg) & 15) << 12 2393 o1 |= (uint32(p.From.Reg) & 15) << 0 2394 2395 case 98: /* MULW{T,B} Rs, Rm, Rd */ 2396 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2397 2398 o1 |= (uint32(p.To.Reg) & 15) << 16 2399 o1 |= (uint32(p.From.Reg) & 15) << 8 2400 o1 |= (uint32(p.Reg) & 15) << 0 2401 2402 case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ 2403 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2404 2405 o1 |= (uint32(p.To.Reg) & 15) << 12 2406 o1 |= (uint32(p.From.Reg) & 15) << 8 2407 o1 |= (uint32(p.Reg) & 15) << 0 2408 o1 |= uint32((p.To.Offset & 15) << 16) 2409 2410 // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle; 2411 // DATABUNDLEEND: zero width alignment marker 2412 case 100: 2413 if p.As == ADATABUNDLE { 2414 o1 = 0xe125be70 2415 } 2416 } 2417 2418 out[0] = o1 2419 out[1] = o2 2420 out[2] = o3 2421 out[3] = o4 2422 out[4] = o5 2423 out[5] = o6 2424 return 2425 } 2426 2427 func mov(ctxt *obj.Link, p *obj.Prog) uint32 { 2428 aclass(ctxt, &p.From) 2429 o1 := oprrr(ctxt, int(p.As), int(p.Scond)) 2430 o1 |= uint32(p.From.Offset) 2431 rt := int(p.To.Reg) 2432 if p.To.Type == obj.TYPE_NONE { 2433 rt = 0 2434 } 2435 r := int(p.Reg) 2436 if p.As == AMOVW || p.As == AMVN { 2437 r = 0 2438 } else if r == 0 { 2439 r = rt 2440 } 2441 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 2442 return o1 2443 } 2444 2445 func oprrr(ctxt *obj.Link, a int, sc int) uint32 { 2446 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2447 if sc&C_SBIT != 0 { 2448 o |= 1 << 20 2449 } 2450 if sc&(C_PBIT|C_WBIT) != 0 { 2451 ctxt.Diag(".nil/.W on dp instruction") 2452 } 2453 switch a { 2454 case AMULU, AMUL: 2455 return o | 0x0<<21 | 0x9<<4 2456 case AMULA: 2457 return o | 0x1<<21 | 0x9<<4 2458 case AMULLU: 2459 return o | 0x4<<21 | 0x9<<4 2460 case AMULL: 2461 return o | 0x6<<21 | 0x9<<4 2462 case AMULALU: 2463 return o | 0x5<<21 | 0x9<<4 2464 case AMULAL: 2465 return o | 0x7<<21 | 0x9<<4 2466 case AAND: 2467 return o | 0x0<<21 2468 case AEOR: 2469 return o | 0x1<<21 2470 case ASUB: 2471 return o | 0x2<<21 2472 case ARSB: 2473 return o | 0x3<<21 2474 case AADD: 2475 return o | 0x4<<21 2476 case AADC: 2477 return o | 0x5<<21 2478 case ASBC: 2479 return o | 0x6<<21 2480 case ARSC: 2481 return o | 0x7<<21 2482 case ATST: 2483 return o | 0x8<<21 | 1<<20 2484 case ATEQ: 2485 return o | 0x9<<21 | 1<<20 2486 case ACMP: 2487 return o | 0xa<<21 | 1<<20 2488 case ACMN: 2489 return o | 0xb<<21 | 1<<20 2490 case AORR: 2491 return o | 0xc<<21 2492 2493 case AMOVB, AMOVH, AMOVW: 2494 return o | 0xd<<21 2495 case ABIC: 2496 return o | 0xe<<21 2497 case AMVN: 2498 return o | 0xf<<21 2499 case ASLL: 2500 return o | 0xd<<21 | 0<<5 2501 case ASRL: 2502 return o | 0xd<<21 | 1<<5 2503 case ASRA: 2504 return o | 0xd<<21 | 2<<5 2505 case ASWI: 2506 return o | 0xf<<24 2507 2508 case AADDD: 2509 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4 2510 case AADDF: 2511 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4 2512 case ASUBD: 2513 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4 2514 case ASUBF: 2515 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4 2516 case AMULD: 2517 return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4 2518 case AMULF: 2519 return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4 2520 case ADIVD: 2521 return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4 2522 case ADIVF: 2523 return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4 2524 case ASQRTD: 2525 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4 2526 case ASQRTF: 2527 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4 2528 case AABSD: 2529 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4 2530 case AABSF: 2531 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4 2532 case ACMPD: 2533 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4 2534 case ACMPF: 2535 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4 2536 2537 case AMOVF: 2538 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4 2539 case AMOVD: 2540 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4 2541 2542 case AMOVDF: 2543 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof 2544 case AMOVFD: 2545 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof 2546 2547 case AMOVWF: 2548 if sc&C_UBIT == 0 { 2549 o |= 1 << 7 /* signed */ 2550 } 2551 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double 2552 2553 case AMOVWD: 2554 if sc&C_UBIT == 0 { 2555 o |= 1 << 7 /* signed */ 2556 } 2557 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double 2558 2559 case AMOVFW: 2560 if sc&C_UBIT == 0 { 2561 o |= 1 << 16 /* signed */ 2562 } 2563 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc 2564 2565 case AMOVDW: 2566 if sc&C_UBIT == 0 { 2567 o |= 1 << 16 /* signed */ 2568 } 2569 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc 2570 2571 case AMOVWF + ALAST: // copy WtoF 2572 return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4 2573 2574 case AMOVFW + ALAST: // copy FtoW 2575 return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4 2576 2577 case ACMP + ALAST: // cmp imm 2578 return o | 0x3<<24 | 0x5<<20 2579 2580 // CLZ doesn't support .nil 2581 case ACLZ: 2582 return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4 2583 2584 case AMULWT: 2585 return o&(0xf<<28) | 0x12<<20 | 0xe<<4 2586 2587 case AMULWB: 2588 return o&(0xf<<28) | 0x12<<20 | 0xa<<4 2589 2590 case AMULAWT: 2591 return o&(0xf<<28) | 0x12<<20 | 0xc<<4 2592 2593 case AMULAWB: 2594 return o&(0xf<<28) | 0x12<<20 | 0x8<<4 2595 2596 case ABL: // BLX REG 2597 return o&(0xf<<28) | 0x12fff3<<4 2598 } 2599 2600 ctxt.Diag("bad rrr %d", a) 2601 prasm(ctxt.Curp) 2602 return 0 2603 } 2604 2605 func opbra(ctxt *obj.Link, a int, sc int) uint32 { 2606 if sc&(C_SBIT|C_PBIT|C_WBIT) != 0 { 2607 ctxt.Diag(".nil/.nil/.W on bra instruction") 2608 } 2609 sc &= C_SCOND 2610 sc ^= C_SCOND_XOR 2611 if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY { 2612 return uint32(sc)<<28 | 0x5<<25 | 0x1<<24 2613 } 2614 if sc != 0xe { 2615 ctxt.Diag(".COND on bcond instruction") 2616 } 2617 switch a { 2618 case ABEQ: 2619 return 0x0<<28 | 0x5<<25 2620 case ABNE: 2621 return 0x1<<28 | 0x5<<25 2622 case ABCS: 2623 return 0x2<<28 | 0x5<<25 2624 case ABHS: 2625 return 0x2<<28 | 0x5<<25 2626 case ABCC: 2627 return 0x3<<28 | 0x5<<25 2628 case ABLO: 2629 return 0x3<<28 | 0x5<<25 2630 case ABMI: 2631 return 0x4<<28 | 0x5<<25 2632 case ABPL: 2633 return 0x5<<28 | 0x5<<25 2634 case ABVS: 2635 return 0x6<<28 | 0x5<<25 2636 case ABVC: 2637 return 0x7<<28 | 0x5<<25 2638 case ABHI: 2639 return 0x8<<28 | 0x5<<25 2640 case ABLS: 2641 return 0x9<<28 | 0x5<<25 2642 case ABGE: 2643 return 0xa<<28 | 0x5<<25 2644 case ABLT: 2645 return 0xb<<28 | 0x5<<25 2646 case ABGT: 2647 return 0xc<<28 | 0x5<<25 2648 case ABLE: 2649 return 0xd<<28 | 0x5<<25 2650 case AB: 2651 return 0xe<<28 | 0x5<<25 2652 } 2653 2654 ctxt.Diag("bad bra %v", obj.Aconv(a)) 2655 prasm(ctxt.Curp) 2656 return 0 2657 } 2658 2659 func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 { 2660 if sc&C_SBIT != 0 { 2661 ctxt.Diag(".nil on LDR/STR instruction") 2662 } 2663 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2664 if sc&C_PBIT == 0 { 2665 o |= 1 << 24 2666 } 2667 if sc&C_UBIT == 0 { 2668 o |= 1 << 23 2669 } 2670 if sc&C_WBIT != 0 { 2671 o |= 1 << 21 2672 } 2673 o |= 1<<26 | 1<<20 2674 if v < 0 { 2675 if sc&C_UBIT != 0 { 2676 ctxt.Diag(".U on neg offset") 2677 } 2678 v = -v 2679 o ^= 1 << 23 2680 } 2681 2682 if v >= 1<<12 || v < 0 { 2683 ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp) 2684 } 2685 o |= uint32(v) 2686 o |= (uint32(b) & 15) << 16 2687 o |= (uint32(r) & 15) << 12 2688 return o 2689 } 2690 2691 func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 { 2692 if sc&C_SBIT != 0 { 2693 ctxt.Diag(".nil on LDRH/STRH instruction") 2694 } 2695 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2696 if sc&C_PBIT == 0 { 2697 o |= 1 << 24 2698 } 2699 if sc&C_WBIT != 0 { 2700 o |= 1 << 21 2701 } 2702 o |= 1<<23 | 1<<20 | 0xb<<4 2703 if v < 0 { 2704 v = -v 2705 o ^= 1 << 23 2706 } 2707 2708 if v >= 1<<8 || v < 0 { 2709 ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp) 2710 } 2711 o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22 2712 o |= (uint32(b) & 15) << 16 2713 o |= (uint32(r) & 15) << 12 2714 return o 2715 } 2716 2717 func osr(ctxt *obj.Link, a int, r int, v int32, b int, sc int) uint32 { 2718 o := olr(ctxt, v, b, r, sc) ^ (1 << 20) 2719 if a != AMOVW { 2720 o |= 1 << 22 2721 } 2722 return o 2723 } 2724 2725 func oshr(ctxt *obj.Link, r int, v int32, b int, sc int) uint32 { 2726 o := olhr(ctxt, v, b, r, sc) ^ (1 << 20) 2727 return o 2728 } 2729 2730 func osrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 { 2731 return olr(ctxt, int32(i), b, r, sc) ^ (1<<25 | 1<<20) 2732 } 2733 2734 func oshrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 { 2735 return olhr(ctxt, int32(i), b, r, sc) ^ (1<<22 | 1<<20) 2736 } 2737 2738 func olrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 { 2739 return olr(ctxt, int32(i), b, r, sc) ^ (1 << 25) 2740 } 2741 2742 func olhrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 { 2743 return olhr(ctxt, int32(i), b, r, sc) ^ (1 << 22) 2744 } 2745 2746 func ofsr(ctxt *obj.Link, a int, r int, v int32, b int, sc int, p *obj.Prog) uint32 { 2747 if sc&C_SBIT != 0 { 2748 ctxt.Diag(".nil on FLDR/FSTR instruction") 2749 } 2750 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2751 if sc&C_PBIT == 0 { 2752 o |= 1 << 24 2753 } 2754 if sc&C_WBIT != 0 { 2755 o |= 1 << 21 2756 } 2757 o |= 6<<25 | 1<<24 | 1<<23 | 10<<8 2758 if v < 0 { 2759 v = -v 2760 o ^= 1 << 23 2761 } 2762 2763 if v&3 != 0 { 2764 ctxt.Diag("odd offset for floating point op: %d\n%v", v, p) 2765 } else if v >= 1<<10 || v < 0 { 2766 ctxt.Diag("literal span too large: %d\n%v", v, p) 2767 } 2768 o |= (uint32(v) >> 2) & 0xFF 2769 o |= (uint32(b) & 15) << 16 2770 o |= (uint32(r) & 15) << 12 2771 2772 switch a { 2773 default: 2774 ctxt.Diag("bad fst %v", obj.Aconv(a)) 2775 fallthrough 2776 2777 case AMOVD: 2778 o |= 1 << 8 2779 fallthrough 2780 2781 case AMOVF: 2782 break 2783 } 2784 2785 return o 2786 } 2787 2788 func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 { 2789 var o1 uint32 2790 if p.Pcond == nil { 2791 aclass(ctxt, a) 2792 v := immrot(^uint32(ctxt.Instoffset)) 2793 if v == 0 { 2794 ctxt.Diag("missing literal") 2795 prasm(p) 2796 return 0 2797 } 2798 2799 o1 = oprrr(ctxt, AMVN, int(p.Scond)&C_SCOND) 2800 o1 |= uint32(v) 2801 o1 |= (uint32(dr) & 15) << 12 2802 } else { 2803 v := int32(p.Pcond.Pc - p.Pc - 8) 2804 o1 = olr(ctxt, v, REGPC, dr, int(p.Scond)&C_SCOND) 2805 } 2806 2807 return o1 2808 } 2809 2810 func chipzero5(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 || e != 0 { 2813 return -1 2814 } 2815 return 0 2816 } 2817 2818 func chipfloat5(ctxt *obj.Link, e float64) int { 2819 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 2820 if ctxt.Goarm < 7 { 2821 return -1 2822 } 2823 2824 ei := math.Float64bits(e) 2825 l := uint32(ei) 2826 h := uint32(ei >> 32) 2827 2828 if l != 0 || h&0xffff != 0 { 2829 return -1 2830 } 2831 h1 := h & 0x7fc00000 2832 if h1 != 0x40000000 && h1 != 0x3fc00000 { 2833 return -1 2834 } 2835 n := 0 2836 2837 // sign bit (a) 2838 if h&0x80000000 != 0 { 2839 n |= 1 << 7 2840 } 2841 2842 // exp sign bit (b) 2843 if h1 == 0x3fc00000 { 2844 n |= 1 << 6 2845 } 2846 2847 // rest of exp and mantissa (cd-efgh) 2848 n |= int((h >> 16) & 0x3f) 2849 2850 //print("match %.8lux %.8lux %d\n", l, h, n); 2851 return n 2852 }