github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/cmd/internal/obj/arm/asm5.go (about) 1 // Inferno utils/5l/span.c 2 // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/span.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 package arm 32 33 import ( 34 "cmd/internal/obj" 35 "fmt" 36 "log" 37 "math" 38 "sort" 39 ) 40 41 type Optab struct { 42 as obj.As 43 a1 uint8 44 a2 int8 45 a3 uint8 46 type_ uint8 47 size int8 48 param int16 49 flag int8 50 pcrelsiz uint8 51 } 52 53 type Opcross [32][2][32]uint8 54 55 const ( 56 LFROM = 1 << 0 57 LTO = 1 << 1 58 LPOOL = 1 << 2 59 LPCREL = 1 << 3 60 ) 61 62 var optab = []Optab{ 63 /* struct Optab: 64 OPCODE, from, prog->reg, to, type,size,param,flag */ 65 {obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0}, 66 {AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0}, 67 {AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, 68 {AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, 69 {AMVN, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, 70 {ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0}, 71 {AADD, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0}, 72 {AADD, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0}, 73 {AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0}, 74 {AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0}, 75 {ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0, 0, 0}, 76 {AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0}, 77 {AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0}, 78 {AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0}, 79 {ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0}, 80 {AMOVW, C_RACON, C_NONE, C_REG, 4, 4, REGSP, 0, 0}, 81 {AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL, 0}, 82 {ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, 83 {ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0, 0, 0}, 84 {ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, 85 {ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // prediction hinted form, hint ignored 86 87 {AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL, 0}, 88 {ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0, 0, 0}, 89 {ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0, 0, 0}, 90 {ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0, 0, 0}, 91 {ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0, 0, 0}, 92 {ASLL, C_RCON, C_REG, C_REG, 8, 4, 0, 0, 0}, 93 {ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0, 0, 0}, 94 {ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0}, 95 {ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0}, 96 {ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0}, 97 {ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0, 0, 0}, 98 {ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0, 0, 0}, 99 {AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0, 0, 0}, 100 {AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0, 0, 0}, 101 {AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0, 0, 0}, 102 {AWORD, C_NONE, C_NONE, C_TLS_LE, 103, 4, 0, 0, 0}, 103 {AWORD, C_NONE, C_NONE, C_TLS_IE, 104, 4, 0, 0, 0}, 104 {AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0}, 105 {AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0}, 106 {AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4}, 107 {AADD, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0}, 108 {AADD, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0}, 109 {AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0}, 110 {ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0, 0, 0}, 111 {AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0}, 112 {AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0}, 113 {AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0}, 114 {ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0}, 115 {AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, 116 {AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0}, 117 {AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0, 0, 0}, 118 {AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, 119 {AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0}, 120 {AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0}, 121 {AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0}, 122 {AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0}, 123 {ADIV, C_REG, C_REG, C_REG, 16, 4, 0, 0, 0}, 124 {ADIV, C_REG, C_NONE, C_REG, 16, 4, 0, 0, 0}, 125 {AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0}, 126 {AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0, 0, 0}, 127 {AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0}, 128 {AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0}, 129 {AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0}, 130 {AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0}, 131 {AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0}, 132 {AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0}, 133 {AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0}, 134 {AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0}, 135 {AMOVW, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, 136 {AMOVW, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0}, 137 {AMOVBU, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, 138 {AMOVBU, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0}, 139 {AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, 140 {AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, 141 {AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4}, 142 {AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, 143 {AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, 144 {AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4}, 145 {AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, 146 {AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, 147 {AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4}, 148 {AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, 149 {AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, 150 {AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4}, 151 {AMOVW, C_TLS_LE, C_NONE, C_REG, 101, 4, 0, LFROM, 0}, 152 {AMOVW, C_TLS_IE, C_NONE, C_REG, 102, 8, 0, LFROM, 0}, 153 {AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0}, 154 {AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0}, 155 {AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4}, 156 {AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0}, 157 {AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0}, 158 {AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4}, 159 {AMOVW, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0}, 160 {AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0, 0, 0}, 161 {AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0, 0, 0}, 162 {AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0, 0, 0}, 163 {AMOVM, C_REGLIST, C_NONE, C_SOREG, 38, 4, 0, 0, 0}, 164 {AMOVM, C_SOREG, C_NONE, C_REGLIST, 39, 4, 0, 0, 0}, 165 {ASWPW, C_SOREG, C_REG, C_REG, 40, 4, 0, 0, 0}, 166 {ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0}, 167 {AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP, 0, 0}, 168 {AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0, 0, 0}, 169 {AMOVF, C_FAUTO, C_NONE, C_FREG, 51, 4, REGSP, 0, 0}, 170 {AMOVF, C_FOREG, C_NONE, C_FREG, 51, 4, 0, 0, 0}, 171 {AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO, 0}, 172 {AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO, 0}, 173 {AMOVF, C_LAUTO, C_NONE, C_FREG, 53, 12, REGSP, LFROM, 0}, 174 {AMOVF, C_LOREG, C_NONE, C_FREG, 53, 12, 0, LFROM, 0}, 175 {AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4}, 176 {AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4}, 177 {AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0}, 178 {AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0, 0, 0}, 179 {AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0}, 180 {AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0, 0, 0}, 181 {AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0, 0, 0}, 182 {AMOVW, C_SHIFT, C_NONE, C_REG, 59, 4, 0, 0, 0}, 183 {AMOVBU, C_SHIFT, C_NONE, C_REG, 59, 4, 0, 0, 0}, 184 {AMOVB, C_SHIFT, C_NONE, C_REG, 60, 4, 0, 0, 0}, 185 {AMOVBS, C_SHIFT, C_NONE, C_REG, 60, 4, 0, 0, 0}, 186 {AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0}, 187 {AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0}, 188 {AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0}, 189 {AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0}, 190 {AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0}, 191 {AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0}, 192 {AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0}, 193 {AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0}, 194 {AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0}, 195 {AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0}, 196 {AMOVB, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0}, 197 {AMOVB, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0}, 198 {AMOVBS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0}, 199 {AMOVBS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0}, 200 {AMOVH, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0}, 201 {AMOVH, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0}, 202 {AMOVHS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0}, 203 {AMOVHS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0}, 204 {AMOVHU, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0}, 205 {AMOVHU, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0}, 206 {AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0}, 207 {AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0}, 208 {AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4}, 209 {AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0}, 210 {AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0}, 211 {AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4}, 212 {AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0}, 213 {AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0}, 214 {AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4}, 215 {AMOVB, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0}, 216 {AMOVB, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0}, 217 {AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4}, 218 {AMOVBS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0}, 219 {AMOVBS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0}, 220 {AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4}, 221 {AMOVH, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0}, 222 {AMOVH, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0}, 223 {AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4}, 224 {AMOVHS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0}, 225 {AMOVHS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0}, 226 {AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4}, 227 {AMOVHU, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0}, 228 {AMOVHU, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0}, 229 {AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4}, 230 {ALDREX, C_SOREG, C_NONE, C_REG, 77, 4, 0, 0, 0}, 231 {ASTREX, C_SOREG, C_REG, C_REG, 78, 4, 0, 0, 0}, 232 {AMOVF, C_ZFCON, C_NONE, C_FREG, 80, 8, 0, 0, 0}, 233 {AMOVF, C_SFCON, C_NONE, C_FREG, 81, 4, 0, 0, 0}, 234 {ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0, 0, 0}, 235 {ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0, 0, 0}, 236 {AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0, 0, 0}, 237 {AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0, 0, 0}, 238 {AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0, 0, 0}, 239 {AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0, 0, 0}, 240 {AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0, 0, 0}, 241 {AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0, 0, 0}, 242 {ATST, C_REG, C_NONE, C_NONE, 90, 4, 0, 0, 0}, 243 {ALDREXD, C_SOREG, C_NONE, C_REG, 91, 4, 0, 0, 0}, 244 {ASTREXD, C_SOREG, C_REG, C_REG, 92, 4, 0, 0, 0}, 245 {APLD, C_SOREG, C_NONE, C_NONE, 95, 4, 0, 0, 0}, 246 {obj.AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0, 0, 0}, 247 {ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0}, 248 {AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0}, 249 {AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0}, 250 {obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0, 0}, 251 {obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0}, 252 {obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0}, 253 {obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, 254 {obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as ABL 255 {obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as ABL 256 257 {ADATABUNDLE, C_NONE, C_NONE, C_NONE, 100, 4, 0, 0, 0}, 258 {ADATABUNDLEEND, C_NONE, C_NONE, C_NONE, 100, 0, 0, 0, 0}, 259 {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0}, 260 } 261 262 var pool struct { 263 start uint32 264 size uint32 265 extra uint32 266 } 267 268 var oprange [ALAST & obj.AMask][]Optab 269 270 var xcmp [C_GOK + 1][C_GOK + 1]bool 271 272 var deferreturn *obj.LSym 273 274 // Note about encoding: Prog.scond holds the condition encoding, 275 // but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0. 276 // The code that shifts the value << 28 has the responsibility 277 // for XORing with C_SCOND_XOR too. 278 279 // asmoutnacl assembles the instruction p. It replaces asmout for NaCl. 280 // It returns the total number of bytes put in out, and it can change 281 // p->pc if extra padding is necessary. 282 // In rare cases, asmoutnacl might split p into two instructions. 283 // origPC is the PC for this Prog (no padding is taken into account). 284 func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint32) int { 285 size := int(o.size) 286 287 // instruction specific 288 switch p.As { 289 default: 290 if out != nil { 291 asmout(ctxt, p, o, out) 292 } 293 294 case ADATABUNDLE, // align to 16-byte boundary 295 ADATABUNDLEEND: // zero width instruction, just to align next instruction to 16-byte boundary 296 p.Pc = (p.Pc + 15) &^ 15 297 298 if out != nil { 299 asmout(ctxt, p, o, out) 300 } 301 302 case obj.AUNDEF, 303 APLD: 304 size = 4 305 if out != nil { 306 switch p.As { 307 case obj.AUNDEF: 308 out[0] = 0xe7fedef0 // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0) 309 310 case APLD: 311 out[0] = 0xe1a01001 // (MOVW R1, R1) 312 } 313 } 314 315 case AB, ABL: 316 if p.To.Type != obj.TYPE_MEM { 317 if out != nil { 318 asmout(ctxt, p, o, out) 319 } 320 } else { 321 if p.To.Offset != 0 || size != 4 || p.To.Reg > REG_R15 || p.To.Reg < REG_R0 { 322 ctxt.Diag("unsupported instruction: %v", p) 323 } 324 if p.Pc&15 == 12 { 325 p.Pc += 4 326 } 327 if out != nil { 328 out[0] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03c0013f | (uint32(p.To.Reg)&15)<<12 | (uint32(p.To.Reg)&15)<<16 // BIC $0xc000000f, Rx 329 if p.As == AB { 330 out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff10 | (uint32(p.To.Reg)&15)<<0 // BX Rx 331 } else { // ABL 332 out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff30 | (uint32(p.To.Reg)&15)<<0 // BLX Rx 333 } 334 } 335 336 size = 8 337 } 338 339 // align the last instruction (the actual BL) to the last instruction in a bundle 340 if p.As == ABL { 341 if deferreturn == nil { 342 deferreturn = obj.Linklookup(ctxt, "runtime.deferreturn", 0) 343 } 344 if p.To.Sym == deferreturn { 345 p.Pc = ((int64(origPC) + 15) &^ 15) + 16 - int64(size) 346 } else { 347 p.Pc += (16 - ((p.Pc + int64(size)) & 15)) & 15 348 } 349 } 350 351 case ALDREX, 352 ALDREXD, 353 AMOVB, 354 AMOVBS, 355 AMOVBU, 356 AMOVD, 357 AMOVF, 358 AMOVH, 359 AMOVHS, 360 AMOVHU, 361 AMOVM, 362 AMOVW, 363 ASTREX, 364 ASTREXD: 365 if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 && p.From.Reg == REG_R13 { // MOVW.W x(R13), PC 366 if out != nil { 367 asmout(ctxt, p, o, out) 368 } 369 if size == 4 { 370 if out != nil { 371 // Note: 5c and 5g reg.c know that DIV/MOD smashes R12 372 // so that this return instruction expansion is valid. 373 out[0] = out[0] &^ 0x3000 // change PC to R12 374 out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03ccc13f // BIC $0xc000000f, R12 375 out[2] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff1c // BX R12 376 } 377 378 size += 8 379 if (p.Pc+int64(size))&15 == 4 { 380 p.Pc += 4 381 } 382 break 383 } else { 384 // if the instruction used more than 4 bytes, then it must have used a very large 385 // offset to update R13, so we need to additionally mask R13. 386 if out != nil { 387 out[size/4-1] &^= 0x3000 // change PC to R12 388 out[size/4] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03cdd103 // BIC $0xc0000000, R13 389 out[size/4+1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03ccc13f // BIC $0xc000000f, R12 390 out[size/4+2] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff1c // BX R12 391 } 392 393 // p->pc+size is only ok at 4 or 12 mod 16. 394 if (p.Pc+int64(size))%8 == 0 { 395 p.Pc += 4 396 } 397 size += 12 398 break 399 } 400 } 401 402 if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 { 403 ctxt.Diag("unsupported instruction (move to another register and use indirect jump instead): %v", p) 404 } 405 406 if p.To.Type == obj.TYPE_MEM && p.To.Reg == REG_R13 && (p.Scond&C_WBIT != 0) && size > 4 { 407 // function prolog with very large frame size: MOVW.W R14,-100004(R13) 408 // split it into two instructions: 409 // ADD $-100004, R13 410 // MOVW R14, 0(R13) 411 q := ctxt.NewProg() 412 413 p.Scond &^= C_WBIT 414 *q = *p 415 a := &p.To 416 var a2 *obj.Addr 417 if p.To.Type == obj.TYPE_MEM { 418 a2 = &q.To 419 } else { 420 a2 = &q.From 421 } 422 nocache(q) 423 nocache(p) 424 425 // insert q after p 426 q.Link = p.Link 427 428 p.Link = q 429 q.Pcond = nil 430 431 // make p into ADD $X, R13 432 p.As = AADD 433 434 p.From = *a 435 p.From.Reg = 0 436 p.From.Type = obj.TYPE_CONST 437 p.To = obj.Addr{} 438 p.To.Type = obj.TYPE_REG 439 p.To.Reg = REG_R13 440 441 // make q into p but load/store from 0(R13) 442 q.Spadj = 0 443 444 *a2 = obj.Addr{} 445 a2.Type = obj.TYPE_MEM 446 a2.Reg = REG_R13 447 a2.Sym = nil 448 a2.Offset = 0 449 size = int(oplook(ctxt, p).size) 450 break 451 } 452 453 if (p.To.Type == obj.TYPE_MEM && p.To.Reg != REG_R9) || // MOVW Rx, X(Ry), y != 9 454 (p.From.Type == obj.TYPE_MEM && p.From.Reg != REG_R9) { // MOVW X(Rx), Ry, x != 9 455 var a *obj.Addr 456 if p.To.Type == obj.TYPE_MEM { 457 a = &p.To 458 } else { 459 a = &p.From 460 } 461 reg := int(a.Reg) 462 if size == 4 { 463 // if addr.reg == 0, then it is probably load from x(FP) with small x, no need to modify. 464 if reg == 0 { 465 if out != nil { 466 asmout(ctxt, p, o, out) 467 } 468 } else { 469 if out != nil { 470 out[0] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03c00103 | (uint32(reg)&15)<<16 | (uint32(reg)&15)<<12 // BIC $0xc0000000, Rx 471 } 472 if p.Pc&15 == 12 { 473 p.Pc += 4 474 } 475 size += 4 476 if out != nil { 477 asmout(ctxt, p, o, out[1:]) 478 } 479 } 480 481 break 482 } else { 483 // if a load/store instruction takes more than 1 word to implement, then 484 // we need to separate the instruction into two: 485 // 1. explicitly load the address into R11. 486 // 2. load/store from R11. 487 // This won't handle .W/.P, so we should reject such code. 488 if p.Scond&(C_PBIT|C_WBIT) != 0 { 489 ctxt.Diag("unsupported instruction (.P/.W): %v", p) 490 } 491 q := ctxt.NewProg() 492 *q = *p 493 var a2 *obj.Addr 494 if p.To.Type == obj.TYPE_MEM { 495 a2 = &q.To 496 } else { 497 a2 = &q.From 498 } 499 nocache(q) 500 nocache(p) 501 502 // insert q after p 503 q.Link = p.Link 504 505 p.Link = q 506 q.Pcond = nil 507 508 // make p into MOVW $X(R), R11 509 p.As = AMOVW 510 511 p.From = *a 512 p.From.Type = obj.TYPE_ADDR 513 p.To = obj.Addr{} 514 p.To.Type = obj.TYPE_REG 515 p.To.Reg = REG_R11 516 517 // make q into p but load/store from 0(R11) 518 *a2 = obj.Addr{} 519 520 a2.Type = obj.TYPE_MEM 521 a2.Reg = REG_R11 522 a2.Sym = nil 523 a2.Offset = 0 524 size = int(oplook(ctxt, p).size) 525 break 526 } 527 } else if out != nil { 528 asmout(ctxt, p, o, out) 529 } 530 } 531 532 // destination register specific 533 if p.To.Type == obj.TYPE_REG { 534 switch p.To.Reg { 535 case REG_R9: 536 ctxt.Diag("invalid instruction, cannot write to R9: %v", p) 537 538 case REG_R13: 539 if out != nil { 540 out[size/4] = 0xe3cdd103 // BIC $0xc0000000, R13 541 } 542 if (p.Pc+int64(size))&15 == 0 { 543 p.Pc += 4 544 } 545 size += 4 546 } 547 } 548 549 return size 550 } 551 552 func span5(ctxt *obj.Link, cursym *obj.LSym) { 553 var p *obj.Prog 554 var op *obj.Prog 555 556 p = cursym.Text 557 if p == nil || p.Link == nil { // handle external functions and ELF section symbols 558 return 559 } 560 561 if oprange[AAND&obj.AMask] == nil { 562 buildop(ctxt) 563 } 564 565 ctxt.Cursym = cursym 566 567 ctxt.Autosize = int32(p.To.Offset + 4) 568 c := int32(0) 569 570 op = p 571 p = p.Link 572 var i int 573 var m int 574 var o *Optab 575 for ; p != nil || ctxt.Blitrl != nil; op, p = p, p.Link { 576 if p == nil { 577 if checkpool(ctxt, op, 0) { 578 p = op 579 continue 580 } 581 582 // can't happen: blitrl is not nil, but checkpool didn't flushpool 583 ctxt.Diag("internal inconsistency") 584 585 break 586 } 587 588 ctxt.Curp = p 589 p.Pc = int64(c) 590 o = oplook(ctxt, p) 591 if ctxt.Headtype != obj.Hnacl { 592 m = int(o.size) 593 } else { 594 m = asmoutnacl(ctxt, c, p, o, nil) 595 c = int32(p.Pc) // asmoutnacl might change pc for alignment 596 o = oplook(ctxt, p) // asmoutnacl might change p in rare cases 597 } 598 599 if m%4 != 0 || p.Pc%4 != 0 { 600 ctxt.Diag("!pc invalid: %v size=%d", p, m) 601 } 602 603 // must check literal pool here in case p generates many instructions 604 if ctxt.Blitrl != nil { 605 i = m 606 if checkpool(ctxt, op, i) { 607 p = op 608 continue 609 } 610 } 611 612 if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) { 613 ctxt.Diag("zero-width instruction\n%v", p) 614 continue 615 } 616 617 switch o.flag & (LFROM | LTO | LPOOL) { 618 case LFROM: 619 addpool(ctxt, p, &p.From) 620 621 case LTO: 622 addpool(ctxt, p, &p.To) 623 624 case LPOOL: 625 if p.Scond&C_SCOND == C_SCOND_NONE { 626 flushpool(ctxt, p, 0, 0) 627 } 628 } 629 630 if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE { 631 flushpool(ctxt, p, 0, 0) 632 } 633 c += int32(m) 634 } 635 636 cursym.Size = int64(c) 637 638 /* 639 * if any procedure is large enough to 640 * generate a large SBRA branch, then 641 * generate extra passes putting branches 642 * around jmps to fix. this is rare. 643 */ 644 times := 0 645 646 var bflag int 647 var opc int32 648 var out [6 + 3]uint32 649 for { 650 if ctxt.Debugvlog != 0 { 651 ctxt.Logf("%5.2f span1\n", obj.Cputime()) 652 } 653 bflag = 0 654 c = 0 655 times++ 656 cursym.Text.Pc = 0 // force re-layout the code. 657 for p = cursym.Text; p != nil; p = p.Link { 658 ctxt.Curp = p 659 o = oplook(ctxt, p) 660 if int64(c) > p.Pc { 661 p.Pc = int64(c) 662 } 663 664 /* very large branches 665 if(o->type == 6 && p->pcond) { 666 otxt = p->pcond->pc - c; 667 if(otxt < 0) 668 otxt = -otxt; 669 if(otxt >= (1L<<17) - 10) { 670 q = emallocz(sizeof(Prog)); 671 q->link = p->link; 672 p->link = q; 673 q->as = AB; 674 q->to.type = TYPE_BRANCH; 675 q->pcond = p->pcond; 676 p->pcond = q; 677 q = emallocz(sizeof(Prog)); 678 q->link = p->link; 679 p->link = q; 680 q->as = AB; 681 q->to.type = TYPE_BRANCH; 682 q->pcond = q->link->link; 683 bflag = 1; 684 } 685 } 686 */ 687 opc = int32(p.Pc) 688 689 if ctxt.Headtype != obj.Hnacl { 690 m = int(o.size) 691 } else { 692 m = asmoutnacl(ctxt, c, p, o, nil) 693 } 694 if p.Pc != int64(opc) { 695 bflag = 1 696 } 697 698 //print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times); 699 c = int32(p.Pc + int64(m)) 700 701 if m%4 != 0 || p.Pc%4 != 0 { 702 ctxt.Diag("pc invalid: %v size=%d", p, m) 703 } 704 705 if m/4 > len(out) { 706 ctxt.Diag("instruction size too large: %d > %d", m/4, len(out)) 707 } 708 if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) { 709 if p.As == obj.ATEXT { 710 ctxt.Autosize = int32(p.To.Offset + 4) 711 continue 712 } 713 714 ctxt.Diag("zero-width instruction\n%v", p) 715 continue 716 } 717 } 718 719 cursym.Size = int64(c) 720 if bflag == 0 { 721 break 722 } 723 } 724 725 if c%4 != 0 { 726 ctxt.Diag("sym->size=%d, invalid", c) 727 } 728 729 /* 730 * lay out the code. all the pc-relative code references, 731 * even cross-function, are resolved now; 732 * only data references need to be relocated. 733 * with more work we could leave cross-function 734 * code references to be relocated too, and then 735 * perhaps we'd be able to parallelize the span loop above. 736 */ 737 738 p = cursym.Text 739 ctxt.Autosize = int32(p.To.Offset + 4) 740 cursym.Grow(cursym.Size) 741 742 bp := cursym.P 743 c = int32(p.Pc) // even p->link might need extra padding 744 var v int 745 for p = p.Link; p != nil; p = p.Link { 746 ctxt.Pc = p.Pc 747 ctxt.Curp = p 748 o = oplook(ctxt, p) 749 opc = int32(p.Pc) 750 if ctxt.Headtype != obj.Hnacl { 751 asmout(ctxt, p, o, out[:]) 752 m = int(o.size) 753 } else { 754 m = asmoutnacl(ctxt, c, p, o, out[:]) 755 if int64(opc) != p.Pc { 756 ctxt.Diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %v", opc, int32(p.Pc), p) 757 } 758 } 759 760 if m%4 != 0 || p.Pc%4 != 0 { 761 ctxt.Diag("final stage: pc invalid: %v size=%d", p, m) 762 } 763 764 if int64(c) > p.Pc { 765 ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, c, p) 766 } 767 for int64(c) != p.Pc { 768 // emit 0xe1a00000 (MOVW R0, R0) 769 bp[0] = 0x00 770 bp = bp[1:] 771 772 bp[0] = 0x00 773 bp = bp[1:] 774 bp[0] = 0xa0 775 bp = bp[1:] 776 bp[0] = 0xe1 777 bp = bp[1:] 778 c += 4 779 } 780 781 for i = 0; i < m/4; i++ { 782 v = int(out[i]) 783 bp[0] = byte(v) 784 bp = bp[1:] 785 bp[0] = byte(v >> 8) 786 bp = bp[1:] 787 bp[0] = byte(v >> 16) 788 bp = bp[1:] 789 bp[0] = byte(v >> 24) 790 bp = bp[1:] 791 } 792 793 c += int32(m) 794 } 795 } 796 797 /* 798 * when the first reference to the literal pool threatens 799 * to go out of range of a 12-bit PC-relative offset, 800 * drop the pool now, and branch round it. 801 * this happens only in extended basic blocks that exceed 4k. 802 */ 803 func checkpool(ctxt *obj.Link, p *obj.Prog, sz int) bool { 804 if pool.size >= 0xff0 || immaddr(int32((p.Pc+int64(sz)+4)+4+int64(12+pool.size)-int64(pool.start+8))) == 0 { 805 return flushpool(ctxt, p, 1, 0) 806 } else if p.Link == nil { 807 return flushpool(ctxt, p, 2, 0) 808 } 809 return false 810 } 811 812 func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool { 813 if ctxt.Blitrl != nil { 814 if skip != 0 { 815 if false && skip == 1 { 816 fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start) 817 } 818 q := ctxt.NewProg() 819 q.As = AB 820 q.To.Type = obj.TYPE_BRANCH 821 q.Pcond = p.Link 822 q.Link = ctxt.Blitrl 823 q.Pos = p.Pos 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.Pos = p.Pos 842 } 843 844 ctxt.Elitrl.Link = p.Link 845 p.Link = ctxt.Blitrl 846 847 ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */ 848 ctxt.Elitrl = nil 849 pool.size = 0 850 pool.start = 0 851 pool.extra = 0 852 return true 853 } 854 855 return false 856 } 857 858 func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { 859 var t obj.Prog 860 861 c := aclass(ctxt, a) 862 863 t.Ctxt = ctxt 864 t.As = AWORD 865 866 switch c { 867 default: 868 t.To.Offset = a.Offset 869 t.To.Sym = a.Sym 870 t.To.Type = a.Type 871 t.To.Name = a.Name 872 873 if ctxt.Flag_shared && t.To.Sym != nil { 874 t.Rel = p 875 } 876 877 case C_SROREG, 878 C_LOREG, 879 C_ROREG, 880 C_FOREG, 881 C_SOREG, 882 C_HOREG, 883 C_FAUTO, 884 C_SAUTO, 885 C_LAUTO, 886 C_LACON: 887 t.To.Type = obj.TYPE_CONST 888 t.To.Offset = ctxt.Instoffset 889 } 890 891 if t.Rel == nil { 892 for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */ 893 if q.Rel == nil && q.To == t.To { 894 p.Pcond = q 895 return 896 } 897 } 898 } 899 900 if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 { 901 // start a new data bundle 902 q := ctxt.NewProg() 903 q.As = ADATABUNDLE 904 q.Pc = int64(pool.size) 905 pool.size += 4 906 if ctxt.Blitrl == nil { 907 ctxt.Blitrl = q 908 pool.start = uint32(p.Pc) 909 } else { 910 ctxt.Elitrl.Link = q 911 } 912 913 ctxt.Elitrl = q 914 } 915 916 q := ctxt.NewProg() 917 *q = t 918 q.Pc = int64(pool.size) 919 920 if ctxt.Blitrl == nil { 921 ctxt.Blitrl = q 922 pool.start = uint32(p.Pc) 923 } else { 924 ctxt.Elitrl.Link = q 925 } 926 ctxt.Elitrl = q 927 pool.size += 4 928 929 p.Pcond = q 930 } 931 932 func regoff(ctxt *obj.Link, a *obj.Addr) int32 { 933 ctxt.Instoffset = 0 934 aclass(ctxt, a) 935 return int32(ctxt.Instoffset) 936 } 937 938 func immrot(v uint32) int32 { 939 for i := 0; i < 16; i++ { 940 if v&^0xff == 0 { 941 return int32(uint32(int32(i)<<8) | v | 1<<25) 942 } 943 v = v<<2 | v>>30 944 } 945 946 return 0 947 } 948 949 func immaddr(v int32) int32 { 950 if v >= 0 && v <= 0xfff { 951 return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */ 952 } 953 if v >= -0xfff && v < 0 { 954 return -v&0xfff | 1<<24 /* pre indexing */ 955 } 956 return 0 957 } 958 959 func immfloat(v int32) bool { 960 return v&0xC03 == 0 /* offset will fit in floating-point load/store */ 961 } 962 963 func immhalf(v int32) bool { 964 if v >= 0 && v <= 0xff { 965 return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */ 966 } 967 if v >= -0xff && v < 0 { 968 return -v&0xff|1<<24 != 0 /* pre indexing */ 969 } 970 return false 971 } 972 973 func aclass(ctxt *obj.Link, a *obj.Addr) int { 974 switch a.Type { 975 case obj.TYPE_NONE: 976 return C_NONE 977 978 case obj.TYPE_REG: 979 ctxt.Instoffset = 0 980 if REG_R0 <= a.Reg && a.Reg <= REG_R15 { 981 return C_REG 982 } 983 if REG_F0 <= a.Reg && a.Reg <= REG_F15 { 984 return C_FREG 985 } 986 if a.Reg == REG_FPSR || a.Reg == REG_FPCR { 987 return C_FCR 988 } 989 if a.Reg == REG_CPSR || a.Reg == REG_SPSR { 990 return C_PSR 991 } 992 return C_GOK 993 994 case obj.TYPE_REGREG: 995 return C_REGREG 996 997 case obj.TYPE_REGREG2: 998 return C_REGREG2 999 1000 case obj.TYPE_REGLIST: 1001 return C_REGLIST 1002 1003 case obj.TYPE_SHIFT: 1004 return C_SHIFT 1005 1006 case obj.TYPE_MEM: 1007 switch a.Name { 1008 case obj.NAME_EXTERN, 1009 obj.NAME_GOTREF, 1010 obj.NAME_STATIC: 1011 if a.Sym == nil || a.Sym.Name == "" { 1012 fmt.Printf("null sym external\n") 1013 return C_GOK 1014 } 1015 1016 ctxt.Instoffset = 0 // s.b. unused but just in case 1017 if a.Sym.Type == obj.STLSBSS { 1018 if ctxt.Flag_shared { 1019 return C_TLS_IE 1020 } else { 1021 return C_TLS_LE 1022 } 1023 } 1024 1025 return C_ADDR 1026 1027 case obj.NAME_AUTO: 1028 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset 1029 if t := immaddr(int32(ctxt.Instoffset)); t != 0 { 1030 if immhalf(int32(ctxt.Instoffset)) { 1031 if immfloat(t) { 1032 return C_HFAUTO 1033 } 1034 return C_HAUTO 1035 } 1036 1037 if immfloat(t) { 1038 return C_FAUTO 1039 } 1040 return C_SAUTO 1041 } 1042 1043 return C_LAUTO 1044 1045 case obj.NAME_PARAM: 1046 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4 1047 if t := immaddr(int32(ctxt.Instoffset)); t != 0 { 1048 if immhalf(int32(ctxt.Instoffset)) { 1049 if immfloat(t) { 1050 return C_HFAUTO 1051 } 1052 return C_HAUTO 1053 } 1054 1055 if immfloat(t) { 1056 return C_FAUTO 1057 } 1058 return C_SAUTO 1059 } 1060 1061 return C_LAUTO 1062 1063 case obj.NAME_NONE: 1064 ctxt.Instoffset = a.Offset 1065 if t := immaddr(int32(ctxt.Instoffset)); t != 0 { 1066 if immhalf(int32(ctxt.Instoffset)) { /* n.b. that it will also satisfy immrot */ 1067 if immfloat(t) { 1068 return C_HFOREG 1069 } 1070 return C_HOREG 1071 } 1072 1073 if immfloat(t) { 1074 return C_FOREG /* n.b. that it will also satisfy immrot */ 1075 } 1076 if immrot(uint32(ctxt.Instoffset)) != 0 { 1077 return C_SROREG 1078 } 1079 if immhalf(int32(ctxt.Instoffset)) { 1080 return C_HOREG 1081 } 1082 return C_SOREG 1083 } 1084 1085 if immrot(uint32(ctxt.Instoffset)) != 0 { 1086 return C_ROREG 1087 } 1088 return C_LOREG 1089 } 1090 1091 return C_GOK 1092 1093 case obj.TYPE_FCONST: 1094 if chipzero5(ctxt, a.Val.(float64)) >= 0 { 1095 return C_ZFCON 1096 } 1097 if chipfloat5(ctxt, a.Val.(float64)) >= 0 { 1098 return C_SFCON 1099 } 1100 return C_LFCON 1101 1102 case obj.TYPE_TEXTSIZE: 1103 return C_TEXTSIZE 1104 1105 case obj.TYPE_CONST, 1106 obj.TYPE_ADDR: 1107 switch a.Name { 1108 case obj.NAME_NONE: 1109 ctxt.Instoffset = a.Offset 1110 if a.Reg != 0 { 1111 return aconsize(ctxt) 1112 } 1113 1114 if immrot(uint32(ctxt.Instoffset)) != 0 { 1115 return C_RCON 1116 } 1117 if immrot(^uint32(ctxt.Instoffset)) != 0 { 1118 return C_NCON 1119 } 1120 return C_LCON 1121 1122 case obj.NAME_EXTERN, 1123 obj.NAME_GOTREF, 1124 obj.NAME_STATIC: 1125 s := a.Sym 1126 if s == nil { 1127 break 1128 } 1129 ctxt.Instoffset = 0 // s.b. unused but just in case 1130 return C_LCONADDR 1131 1132 case obj.NAME_AUTO: 1133 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset 1134 return aconsize(ctxt) 1135 1136 case obj.NAME_PARAM: 1137 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4 1138 return aconsize(ctxt) 1139 } 1140 1141 return C_GOK 1142 1143 case obj.TYPE_BRANCH: 1144 return C_SBRA 1145 } 1146 1147 return C_GOK 1148 } 1149 1150 func aconsize(ctxt *obj.Link) int { 1151 if immrot(uint32(ctxt.Instoffset)) != 0 { 1152 return C_RACON 1153 } 1154 if immrot(uint32(-ctxt.Instoffset)) != 0 { 1155 return C_RACON 1156 } 1157 return C_LACON 1158 } 1159 1160 func prasm(p *obj.Prog) { 1161 fmt.Printf("%v\n", p) 1162 } 1163 1164 func oplook(ctxt *obj.Link, p *obj.Prog) *Optab { 1165 a1 := int(p.Optab) 1166 if a1 != 0 { 1167 return &optab[a1-1] 1168 } 1169 a1 = int(p.From.Class) 1170 if a1 == 0 { 1171 a1 = aclass(ctxt, &p.From) + 1 1172 p.From.Class = int8(a1) 1173 } 1174 1175 a1-- 1176 a3 := int(p.To.Class) 1177 if a3 == 0 { 1178 a3 = aclass(ctxt, &p.To) + 1 1179 p.To.Class = int8(a3) 1180 } 1181 1182 a3-- 1183 a2 := C_NONE 1184 if p.Reg != 0 { 1185 a2 = C_REG 1186 } 1187 1188 if false { /*debug['O']*/ 1189 fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3)) 1190 fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type) 1191 } 1192 1193 ops := oprange[p.As&obj.AMask] 1194 c1 := &xcmp[a1] 1195 c3 := &xcmp[a3] 1196 for i := range ops { 1197 op := &ops[i] 1198 if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] { 1199 p.Optab = uint16(cap(optab) - cap(ops) + i + 1) 1200 return op 1201 } 1202 } 1203 1204 ctxt.Diag("illegal combination %v; %v %v %v, %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.To.Type) 1205 ctxt.Diag("from %d %d to %d %d\n", p.From.Type, p.From.Name, p.To.Type, p.To.Name) 1206 prasm(p) 1207 if ops == nil { 1208 ops = optab 1209 } 1210 return &ops[0] 1211 } 1212 1213 func cmp(a int, b int) bool { 1214 if a == b { 1215 return true 1216 } 1217 switch a { 1218 case C_LCON: 1219 if b == C_RCON || b == C_NCON { 1220 return true 1221 } 1222 1223 case C_LACON: 1224 if b == C_RACON { 1225 return true 1226 } 1227 1228 case C_LFCON: 1229 if b == C_ZFCON || b == C_SFCON { 1230 return true 1231 } 1232 1233 case C_HFAUTO: 1234 return b == C_HAUTO || b == C_FAUTO 1235 1236 case C_FAUTO, C_HAUTO: 1237 return b == C_HFAUTO 1238 1239 case C_SAUTO: 1240 return cmp(C_HFAUTO, b) 1241 1242 case C_LAUTO: 1243 return cmp(C_SAUTO, b) 1244 1245 case C_HFOREG: 1246 return b == C_HOREG || b == C_FOREG 1247 1248 case C_FOREG, C_HOREG: 1249 return b == C_HFOREG 1250 1251 case C_SROREG: 1252 return cmp(C_SOREG, b) || cmp(C_ROREG, b) 1253 1254 case C_SOREG, C_ROREG: 1255 return b == C_SROREG || cmp(C_HFOREG, b) 1256 1257 case C_LOREG: 1258 return cmp(C_SROREG, b) 1259 1260 case C_LBRA: 1261 if b == C_SBRA { 1262 return true 1263 } 1264 1265 case C_HREG: 1266 return cmp(C_SP, b) || cmp(C_PC, b) 1267 } 1268 1269 return false 1270 } 1271 1272 type ocmp []Optab 1273 1274 func (x ocmp) Len() int { 1275 return len(x) 1276 } 1277 1278 func (x ocmp) Swap(i, j int) { 1279 x[i], x[j] = x[j], x[i] 1280 } 1281 1282 func (x ocmp) Less(i, j int) bool { 1283 p1 := &x[i] 1284 p2 := &x[j] 1285 n := int(p1.as) - int(p2.as) 1286 if n != 0 { 1287 return n < 0 1288 } 1289 n = int(p1.a1) - int(p2.a1) 1290 if n != 0 { 1291 return n < 0 1292 } 1293 n = int(p1.a2) - int(p2.a2) 1294 if n != 0 { 1295 return n < 0 1296 } 1297 n = int(p1.a3) - int(p2.a3) 1298 if n != 0 { 1299 return n < 0 1300 } 1301 return false 1302 } 1303 1304 func opset(a, b0 obj.As) { 1305 oprange[a&obj.AMask] = oprange[b0] 1306 } 1307 1308 func buildop(ctxt *obj.Link) { 1309 var n int 1310 1311 for i := 0; i < C_GOK; i++ { 1312 for n = 0; n < C_GOK; n++ { 1313 if cmp(n, i) { 1314 xcmp[i][n] = true 1315 } 1316 } 1317 } 1318 for n = 0; optab[n].as != obj.AXXX; n++ { 1319 if optab[n].flag&LPCREL != 0 { 1320 if ctxt.Flag_shared { 1321 optab[n].size += int8(optab[n].pcrelsiz) 1322 } else { 1323 optab[n].flag &^= LPCREL 1324 } 1325 } 1326 } 1327 1328 sort.Sort(ocmp(optab[:n])) 1329 for i := 0; i < n; i++ { 1330 r := optab[i].as 1331 r0 := r & obj.AMask 1332 start := i 1333 for optab[i].as == r { 1334 i++ 1335 } 1336 oprange[r0] = optab[start:i] 1337 i-- 1338 1339 switch r { 1340 default: 1341 ctxt.Diag("unknown op in build: %v", r) 1342 log.Fatalf("bad code") 1343 1344 case AADD: 1345 opset(AAND, r0) 1346 opset(AEOR, r0) 1347 opset(ASUB, r0) 1348 opset(ARSB, r0) 1349 opset(AADC, r0) 1350 opset(ASBC, r0) 1351 opset(ARSC, r0) 1352 opset(AORR, r0) 1353 opset(ABIC, r0) 1354 1355 case ACMP: 1356 opset(ATEQ, r0) 1357 opset(ACMN, r0) 1358 1359 case AMVN: 1360 break 1361 1362 case ABEQ: 1363 opset(ABNE, r0) 1364 opset(ABCS, r0) 1365 opset(ABHS, r0) 1366 opset(ABCC, r0) 1367 opset(ABLO, r0) 1368 opset(ABMI, r0) 1369 opset(ABPL, r0) 1370 opset(ABVS, r0) 1371 opset(ABVC, r0) 1372 opset(ABHI, r0) 1373 opset(ABLS, r0) 1374 opset(ABGE, r0) 1375 opset(ABLT, r0) 1376 opset(ABGT, r0) 1377 opset(ABLE, r0) 1378 1379 case ASLL: 1380 opset(ASRL, r0) 1381 opset(ASRA, r0) 1382 1383 case AMUL: 1384 opset(AMULU, r0) 1385 1386 case ADIV: 1387 opset(AMOD, r0) 1388 opset(AMODU, r0) 1389 opset(ADIVU, r0) 1390 1391 case AMOVW, 1392 AMOVB, 1393 AMOVBS, 1394 AMOVBU, 1395 AMOVH, 1396 AMOVHS, 1397 AMOVHU: 1398 break 1399 1400 case ASWPW: 1401 opset(ASWPBU, r0) 1402 1403 case AB, 1404 ABL, 1405 ABX, 1406 ABXRET, 1407 obj.ADUFFZERO, 1408 obj.ADUFFCOPY, 1409 ASWI, 1410 AWORD, 1411 AMOVM, 1412 ARFE, 1413 obj.ATEXT, 1414 obj.AUSEFIELD: 1415 break 1416 1417 case AADDF: 1418 opset(AADDD, r0) 1419 opset(ASUBF, r0) 1420 opset(ASUBD, r0) 1421 opset(AMULF, r0) 1422 opset(AMULD, r0) 1423 opset(ADIVF, r0) 1424 opset(ADIVD, r0) 1425 opset(ASQRTF, r0) 1426 opset(ASQRTD, r0) 1427 opset(AMOVFD, r0) 1428 opset(AMOVDF, r0) 1429 opset(AABSF, r0) 1430 opset(AABSD, r0) 1431 opset(ANEGF, r0) 1432 opset(ANEGD, r0) 1433 1434 case ACMPF: 1435 opset(ACMPD, r0) 1436 1437 case AMOVF: 1438 opset(AMOVD, r0) 1439 1440 case AMOVFW: 1441 opset(AMOVDW, r0) 1442 1443 case AMOVWF: 1444 opset(AMOVWD, r0) 1445 1446 case AMULL: 1447 opset(AMULAL, r0) 1448 opset(AMULLU, r0) 1449 opset(AMULALU, r0) 1450 1451 case AMULWT: 1452 opset(AMULWB, r0) 1453 1454 case AMULAWT: 1455 opset(AMULAWB, r0) 1456 1457 case AMULA, 1458 ALDREX, 1459 ASTREX, 1460 ALDREXD, 1461 ASTREXD, 1462 ATST, 1463 APLD, 1464 obj.AUNDEF, 1465 ACLZ, 1466 obj.AFUNCDATA, 1467 obj.APCDATA, 1468 obj.ANOP, 1469 ADATABUNDLE, 1470 ADATABUNDLEEND: 1471 break 1472 } 1473 } 1474 } 1475 1476 func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { 1477 ctxt.Printp = p 1478 o1 := uint32(0) 1479 o2 := uint32(0) 1480 o3 := uint32(0) 1481 o4 := uint32(0) 1482 o5 := uint32(0) 1483 o6 := uint32(0) 1484 ctxt.Armsize += int32(o.size) 1485 if false { /*debug['P']*/ 1486 fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_) 1487 } 1488 switch o.type_ { 1489 default: 1490 ctxt.Diag("unknown asm %d", o.type_) 1491 prasm(p) 1492 1493 case 0: /* pseudo ops */ 1494 if false { /*debug['G']*/ 1495 fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name) 1496 } 1497 1498 case 1: /* op R,[R],R */ 1499 o1 = oprrr(ctxt, p.As, int(p.Scond)) 1500 1501 rf := int(p.From.Reg) 1502 rt := int(p.To.Reg) 1503 r := int(p.Reg) 1504 if p.To.Type == obj.TYPE_NONE { 1505 rt = 0 1506 } 1507 if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN { 1508 r = 0 1509 } else if r == 0 { 1510 r = rt 1511 } 1512 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1513 1514 case 2: /* movbu $I,[R],R */ 1515 aclass(ctxt, &p.From) 1516 1517 o1 = oprrr(ctxt, p.As, int(p.Scond)) 1518 o1 |= uint32(immrot(uint32(ctxt.Instoffset))) 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 == AMOVW || p.As == AMVN { 1525 r = 0 1526 } else if r == 0 { 1527 r = rt 1528 } 1529 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1530 1531 case 3: /* add R<<[IR],[R],R */ 1532 o1 = mov(ctxt, p) 1533 1534 case 4: /* MOVW $off(R), R -> add $off,[R],R */ 1535 aclass(ctxt, &p.From) 1536 if ctxt.Instoffset < 0 { 1537 o1 = oprrr(ctxt, ASUB, int(p.Scond)) 1538 o1 |= uint32(immrot(uint32(-ctxt.Instoffset))) 1539 } else { 1540 o1 = oprrr(ctxt, AADD, int(p.Scond)) 1541 o1 |= uint32(immrot(uint32(ctxt.Instoffset))) 1542 } 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 || p.As == ANEGF || p.As == ANEGD { 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 ANEGD: 2512 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0x4<<4 2513 case ANEGF: 2514 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0x4<<4 2515 case ACMPD: 2516 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4 2517 case ACMPF: 2518 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4 2519 2520 case AMOVF: 2521 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4 2522 case AMOVD: 2523 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4 2524 2525 case AMOVDF: 2526 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof 2527 case AMOVFD: 2528 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof 2529 2530 case AMOVWF: 2531 if sc&C_UBIT == 0 { 2532 o |= 1 << 7 /* signed */ 2533 } 2534 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double 2535 2536 case AMOVWD: 2537 if sc&C_UBIT == 0 { 2538 o |= 1 << 7 /* signed */ 2539 } 2540 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double 2541 2542 case AMOVFW: 2543 if sc&C_UBIT == 0 { 2544 o |= 1 << 16 /* signed */ 2545 } 2546 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc 2547 2548 case AMOVDW: 2549 if sc&C_UBIT == 0 { 2550 o |= 1 << 16 /* signed */ 2551 } 2552 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc 2553 2554 case -AMOVWF: // copy WtoF 2555 return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4 2556 2557 case -AMOVFW: // copy FtoW 2558 return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4 2559 2560 case -ACMP: // cmp imm 2561 return o | 0x3<<24 | 0x5<<20 2562 2563 // CLZ doesn't support .nil 2564 case ACLZ: 2565 return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4 2566 2567 case AMULWT: 2568 return o&(0xf<<28) | 0x12<<20 | 0xe<<4 2569 2570 case AMULWB: 2571 return o&(0xf<<28) | 0x12<<20 | 0xa<<4 2572 2573 case AMULAWT: 2574 return o&(0xf<<28) | 0x12<<20 | 0xc<<4 2575 2576 case AMULAWB: 2577 return o&(0xf<<28) | 0x12<<20 | 0x8<<4 2578 2579 case ABL: // BLX REG 2580 return o&(0xf<<28) | 0x12fff3<<4 2581 } 2582 2583 ctxt.Diag("bad rrr %d", a) 2584 prasm(ctxt.Curp) 2585 return 0 2586 } 2587 2588 func opbra(ctxt *obj.Link, p *obj.Prog, a obj.As, sc int) uint32 { 2589 if sc&(C_SBIT|C_PBIT|C_WBIT) != 0 { 2590 ctxt.Diag("%v: .nil/.nil/.W on bra instruction", p) 2591 } 2592 sc &= C_SCOND 2593 sc ^= C_SCOND_XOR 2594 if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY { 2595 return uint32(sc)<<28 | 0x5<<25 | 0x1<<24 2596 } 2597 if sc != 0xe { 2598 ctxt.Diag("%v: .COND on bcond instruction", p) 2599 } 2600 switch a { 2601 case ABEQ: 2602 return 0x0<<28 | 0x5<<25 2603 case ABNE: 2604 return 0x1<<28 | 0x5<<25 2605 case ABCS: 2606 return 0x2<<28 | 0x5<<25 2607 case ABHS: 2608 return 0x2<<28 | 0x5<<25 2609 case ABCC: 2610 return 0x3<<28 | 0x5<<25 2611 case ABLO: 2612 return 0x3<<28 | 0x5<<25 2613 case ABMI: 2614 return 0x4<<28 | 0x5<<25 2615 case ABPL: 2616 return 0x5<<28 | 0x5<<25 2617 case ABVS: 2618 return 0x6<<28 | 0x5<<25 2619 case ABVC: 2620 return 0x7<<28 | 0x5<<25 2621 case ABHI: 2622 return 0x8<<28 | 0x5<<25 2623 case ABLS: 2624 return 0x9<<28 | 0x5<<25 2625 case ABGE: 2626 return 0xa<<28 | 0x5<<25 2627 case ABLT: 2628 return 0xb<<28 | 0x5<<25 2629 case ABGT: 2630 return 0xc<<28 | 0x5<<25 2631 case ABLE: 2632 return 0xd<<28 | 0x5<<25 2633 case AB: 2634 return 0xe<<28 | 0x5<<25 2635 } 2636 2637 ctxt.Diag("bad bra %v", a) 2638 prasm(ctxt.Curp) 2639 return 0 2640 } 2641 2642 func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 { 2643 if sc&C_SBIT != 0 { 2644 ctxt.Diag(".nil on LDR/STR instruction") 2645 } 2646 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2647 if sc&C_PBIT == 0 { 2648 o |= 1 << 24 2649 } 2650 if sc&C_UBIT == 0 { 2651 o |= 1 << 23 2652 } 2653 if sc&C_WBIT != 0 { 2654 o |= 1 << 21 2655 } 2656 o |= 1<<26 | 1<<20 2657 if v < 0 { 2658 if sc&C_UBIT != 0 { 2659 ctxt.Diag(".U on neg offset") 2660 } 2661 v = -v 2662 o ^= 1 << 23 2663 } 2664 2665 if v >= 1<<12 || v < 0 { 2666 ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp) 2667 } 2668 o |= uint32(v) 2669 o |= (uint32(b) & 15) << 16 2670 o |= (uint32(r) & 15) << 12 2671 return o 2672 } 2673 2674 func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 { 2675 if sc&C_SBIT != 0 { 2676 ctxt.Diag(".nil on LDRH/STRH instruction") 2677 } 2678 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2679 if sc&C_PBIT == 0 { 2680 o |= 1 << 24 2681 } 2682 if sc&C_WBIT != 0 { 2683 o |= 1 << 21 2684 } 2685 o |= 1<<23 | 1<<20 | 0xb<<4 2686 if v < 0 { 2687 v = -v 2688 o ^= 1 << 23 2689 } 2690 2691 if v >= 1<<8 || v < 0 { 2692 ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp) 2693 } 2694 o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22 2695 o |= (uint32(b) & 15) << 16 2696 o |= (uint32(r) & 15) << 12 2697 return o 2698 } 2699 2700 func osr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int) uint32 { 2701 o := olr(ctxt, v, b, r, sc) ^ (1 << 20) 2702 if a != AMOVW { 2703 o |= 1 << 22 2704 } 2705 return o 2706 } 2707 2708 func oshr(ctxt *obj.Link, r int, v int32, b int, sc int) uint32 { 2709 o := olhr(ctxt, v, b, r, sc) ^ (1 << 20) 2710 return o 2711 } 2712 2713 func osrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 { 2714 return olr(ctxt, int32(i), b, r, sc) ^ (1<<25 | 1<<20) 2715 } 2716 2717 func oshrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 { 2718 return olhr(ctxt, int32(i), b, r, sc) ^ (1<<22 | 1<<20) 2719 } 2720 2721 func olrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 { 2722 return olr(ctxt, int32(i), b, r, sc) ^ (1 << 25) 2723 } 2724 2725 func olhrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 { 2726 return olhr(ctxt, int32(i), b, r, sc) ^ (1 << 22) 2727 } 2728 2729 func ofsr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 { 2730 if sc&C_SBIT != 0 { 2731 ctxt.Diag(".nil on FLDR/FSTR instruction: %v", p) 2732 } 2733 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2734 if sc&C_PBIT == 0 { 2735 o |= 1 << 24 2736 } 2737 if sc&C_WBIT != 0 { 2738 o |= 1 << 21 2739 } 2740 o |= 6<<25 | 1<<24 | 1<<23 | 10<<8 2741 if v < 0 { 2742 v = -v 2743 o ^= 1 << 23 2744 } 2745 2746 if v&3 != 0 { 2747 ctxt.Diag("odd offset for floating point op: %d\n%v", v, p) 2748 } else if v >= 1<<10 || v < 0 { 2749 ctxt.Diag("literal span too large: %d\n%v", v, p) 2750 } 2751 o |= (uint32(v) >> 2) & 0xFF 2752 o |= (uint32(b) & 15) << 16 2753 o |= (uint32(r) & 15) << 12 2754 2755 switch a { 2756 default: 2757 ctxt.Diag("bad fst %v", a) 2758 fallthrough 2759 2760 case AMOVD: 2761 o |= 1 << 8 2762 fallthrough 2763 2764 case AMOVF: 2765 break 2766 } 2767 2768 return o 2769 } 2770 2771 func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 { 2772 var o1 uint32 2773 if p.Pcond == nil { 2774 aclass(ctxt, a) 2775 v := immrot(^uint32(ctxt.Instoffset)) 2776 if v == 0 { 2777 ctxt.Diag("missing literal") 2778 prasm(p) 2779 return 0 2780 } 2781 2782 o1 = oprrr(ctxt, AMVN, int(p.Scond)&C_SCOND) 2783 o1 |= uint32(v) 2784 o1 |= (uint32(dr) & 15) << 12 2785 } else { 2786 v := int32(p.Pcond.Pc - p.Pc - 8) 2787 o1 = olr(ctxt, v, REGPC, dr, int(p.Scond)&C_SCOND) 2788 } 2789 2790 return o1 2791 } 2792 2793 func chipzero5(ctxt *obj.Link, e float64) int { 2794 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 2795 if obj.GOARM < 7 || e != 0 { 2796 return -1 2797 } 2798 return 0 2799 } 2800 2801 func chipfloat5(ctxt *obj.Link, e float64) int { 2802 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 2803 if obj.GOARM < 7 { 2804 return -1 2805 } 2806 2807 ei := math.Float64bits(e) 2808 l := uint32(ei) 2809 h := uint32(ei >> 32) 2810 2811 if l != 0 || h&0xffff != 0 { 2812 return -1 2813 } 2814 h1 := h & 0x7fc00000 2815 if h1 != 0x40000000 && h1 != 0x3fc00000 { 2816 return -1 2817 } 2818 n := 0 2819 2820 // sign bit (a) 2821 if h&0x80000000 != 0 { 2822 n |= 1 << 7 2823 } 2824 2825 // exp sign bit (b) 2826 if h1 == 0x3fc00000 { 2827 n |= 1 << 6 2828 } 2829 2830 // rest of exp and mantissa (cd-efgh) 2831 n |= int((h >> 16) & 0x3f) 2832 2833 //print("match %.8lux %.8lux %d\n", l, h, n); 2834 return n 2835 } 2836 2837 func nocache(p *obj.Prog) { 2838 p.Optab = 0 2839 p.From.Class = 0 2840 if p.From3 != nil { 2841 p.From3.Class = 0 2842 } 2843 p.To.Class = 0 2844 }