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