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