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