github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/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_R9) || // MOVW Rx, X(Ry), y != 9 476 (p.From.Type == obj.TYPE_MEM && p.From.Reg != REG_R9) { // MOVW X(Rx), Ry, 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 separate 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("%v 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 // The line number for constant pool entries doesn't really matter. 866 // We set it to the line number of the preceding instruction so that 867 // there are no deltas to encode in the pc-line tables. 868 for q := ctxt.Blitrl; q != nil; q = q.Link { 869 q.Lineno = p.Lineno 870 } 871 872 ctxt.Elitrl.Link = p.Link 873 p.Link = ctxt.Blitrl 874 875 ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */ 876 ctxt.Elitrl = nil 877 pool.size = 0 878 pool.start = 0 879 pool.extra = 0 880 return true 881 } 882 883 return false 884 } 885 886 func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { 887 var t obj.Prog 888 889 c := aclass(ctxt, a) 890 891 t.Ctxt = ctxt 892 t.As = AWORD 893 894 switch c { 895 default: 896 t.To.Offset = a.Offset 897 t.To.Sym = a.Sym 898 t.To.Type = a.Type 899 t.To.Name = a.Name 900 901 if ctxt.Flag_shared != 0 && t.To.Sym != nil { 902 t.Rel = p 903 } 904 905 case C_SROREG, 906 C_LOREG, 907 C_ROREG, 908 C_FOREG, 909 C_SOREG, 910 C_HOREG, 911 C_FAUTO, 912 C_SAUTO, 913 C_LAUTO, 914 C_LACON: 915 t.To.Type = obj.TYPE_CONST 916 t.To.Offset = ctxt.Instoffset 917 } 918 919 if t.Rel == nil { 920 for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */ 921 if q.Rel == nil && q.To == t.To { 922 p.Pcond = q 923 return 924 } 925 } 926 } 927 928 if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 { 929 // start a new data bundle 930 q := ctxt.NewProg() 931 q.As = ADATABUNDLE 932 q.Pc = int64(pool.size) 933 pool.size += 4 934 if ctxt.Blitrl == nil { 935 ctxt.Blitrl = q 936 pool.start = uint32(p.Pc) 937 } else { 938 ctxt.Elitrl.Link = q 939 } 940 941 ctxt.Elitrl = q 942 } 943 944 q := ctxt.NewProg() 945 *q = t 946 q.Pc = int64(pool.size) 947 948 if ctxt.Blitrl == nil { 949 ctxt.Blitrl = q 950 pool.start = uint32(p.Pc) 951 } else { 952 ctxt.Elitrl.Link = q 953 } 954 ctxt.Elitrl = q 955 pool.size += 4 956 957 p.Pcond = q 958 } 959 960 func regoff(ctxt *obj.Link, a *obj.Addr) int32 { 961 ctxt.Instoffset = 0 962 aclass(ctxt, a) 963 return int32(ctxt.Instoffset) 964 } 965 966 func immrot(v uint32) int32 { 967 for i := 0; i < 16; i++ { 968 if v&^0xff == 0 { 969 return int32(uint32(int32(i)<<8) | v | 1<<25) 970 } 971 v = v<<2 | v>>30 972 } 973 974 return 0 975 } 976 977 func immaddr(v int32) int32 { 978 if v >= 0 && v <= 0xfff { 979 return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */ 980 } 981 if v >= -0xfff && v < 0 { 982 return -v&0xfff | 1<<24 /* pre indexing */ 983 } 984 return 0 985 } 986 987 func immfloat(v int32) bool { 988 return v&0xC03 == 0 /* offset will fit in floating-point load/store */ 989 } 990 991 func immhalf(v int32) bool { 992 if v >= 0 && v <= 0xff { 993 return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */ 994 } 995 if v >= -0xff && v < 0 { 996 return -v&0xff|1<<24 != 0 /* pre indexing */ 997 } 998 return false 999 } 1000 1001 func aclass(ctxt *obj.Link, a *obj.Addr) int { 1002 switch a.Type { 1003 case obj.TYPE_NONE: 1004 return C_NONE 1005 1006 case obj.TYPE_REG: 1007 if REG_R0 <= a.Reg && a.Reg <= REG_R15 { 1008 return C_REG 1009 } 1010 if REG_F0 <= a.Reg && a.Reg <= REG_F15 { 1011 return C_FREG 1012 } 1013 if a.Reg == REG_FPSR || a.Reg == REG_FPCR { 1014 return C_FCR 1015 } 1016 if a.Reg == REG_CPSR || a.Reg == REG_SPSR { 1017 return C_PSR 1018 } 1019 return C_GOK 1020 1021 case obj.TYPE_REGREG: 1022 return C_REGREG 1023 1024 case obj.TYPE_REGREG2: 1025 return C_REGREG2 1026 1027 case obj.TYPE_REGLIST: 1028 return C_REGLIST 1029 1030 case obj.TYPE_SHIFT: 1031 return C_SHIFT 1032 1033 case obj.TYPE_MEM: 1034 switch a.Name { 1035 case obj.NAME_EXTERN, 1036 obj.NAME_STATIC: 1037 if a.Sym == nil || a.Sym.Name == "" { 1038 fmt.Printf("null sym external\n") 1039 return C_GOK 1040 } 1041 1042 ctxt.Instoffset = 0 // s.b. unused but just in case 1043 return C_ADDR 1044 1045 case obj.NAME_AUTO: 1046 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset 1047 t := int(immaddr(int32(ctxt.Instoffset))) 1048 if t != 0 { 1049 if immhalf(int32(ctxt.Instoffset)) { 1050 if immfloat(int32(t)) { 1051 return C_HFAUTO 1052 } 1053 return C_HAUTO 1054 } 1055 1056 if immfloat(int32(t)) { 1057 return C_FAUTO 1058 } 1059 return C_SAUTO 1060 } 1061 1062 return C_LAUTO 1063 1064 case obj.NAME_PARAM: 1065 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4 1066 t := int(immaddr(int32(ctxt.Instoffset))) 1067 if t != 0 { 1068 if immhalf(int32(ctxt.Instoffset)) { 1069 if immfloat(int32(t)) { 1070 return C_HFAUTO 1071 } 1072 return C_HAUTO 1073 } 1074 1075 if immfloat(int32(t)) { 1076 return C_FAUTO 1077 } 1078 return C_SAUTO 1079 } 1080 1081 return C_LAUTO 1082 1083 case obj.TYPE_NONE: 1084 ctxt.Instoffset = a.Offset 1085 t := int(immaddr(int32(ctxt.Instoffset))) 1086 if t != 0 { 1087 if immhalf(int32(ctxt.Instoffset)) { /* n.b. that it will also satisfy immrot */ 1088 if immfloat(int32(t)) { 1089 return C_HFOREG 1090 } 1091 return C_HOREG 1092 } 1093 1094 if immfloat(int32(t)) { 1095 return C_FOREG /* n.b. that it will also satisfy immrot */ 1096 } 1097 t := int(immrot(uint32(ctxt.Instoffset))) 1098 if t != 0 { 1099 return C_SROREG 1100 } 1101 if immhalf(int32(ctxt.Instoffset)) { 1102 return C_HOREG 1103 } 1104 return C_SOREG 1105 } 1106 1107 t = int(immrot(uint32(ctxt.Instoffset))) 1108 if t != 0 { 1109 return C_ROREG 1110 } 1111 return C_LOREG 1112 } 1113 1114 return C_GOK 1115 1116 case obj.TYPE_FCONST: 1117 if chipzero5(ctxt, a.Val.(float64)) >= 0 { 1118 return C_ZFCON 1119 } 1120 if chipfloat5(ctxt, a.Val.(float64)) >= 0 { 1121 return C_SFCON 1122 } 1123 return C_LFCON 1124 1125 case obj.TYPE_TEXTSIZE: 1126 return C_TEXTSIZE 1127 1128 case obj.TYPE_CONST, 1129 obj.TYPE_ADDR: 1130 switch a.Name { 1131 case obj.TYPE_NONE: 1132 ctxt.Instoffset = a.Offset 1133 if a.Reg != 0 { 1134 return aconsize(ctxt) 1135 } 1136 1137 t := int(immrot(uint32(ctxt.Instoffset))) 1138 if t != 0 { 1139 return C_RCON 1140 } 1141 t = int(immrot(^uint32(ctxt.Instoffset))) 1142 if t != 0 { 1143 return C_NCON 1144 } 1145 return C_LCON 1146 1147 case obj.NAME_EXTERN, 1148 obj.NAME_STATIC: 1149 s := a.Sym 1150 if s == nil { 1151 break 1152 } 1153 ctxt.Instoffset = 0 // s.b. unused but just in case 1154 return C_LCONADDR 1155 1156 case obj.NAME_AUTO: 1157 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset 1158 return aconsize(ctxt) 1159 1160 case obj.NAME_PARAM: 1161 ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4 1162 return aconsize(ctxt) 1163 } 1164 1165 return C_GOK 1166 1167 case obj.TYPE_BRANCH: 1168 return C_SBRA 1169 } 1170 1171 return C_GOK 1172 } 1173 1174 func aconsize(ctxt *obj.Link) int { 1175 t := int(immrot(uint32(ctxt.Instoffset))) 1176 if t != 0 { 1177 return C_RACON 1178 } 1179 return C_LACON 1180 } 1181 1182 func prasm(p *obj.Prog) { 1183 fmt.Printf("%v\n", p) 1184 } 1185 1186 func oplook(ctxt *obj.Link, p *obj.Prog) *Optab { 1187 a1 := int(p.Optab) 1188 if a1 != 0 { 1189 return &optab[a1-1:][0] 1190 } 1191 a1 = int(p.From.Class) 1192 if a1 == 0 { 1193 a1 = aclass(ctxt, &p.From) + 1 1194 p.From.Class = int8(a1) 1195 } 1196 1197 a1-- 1198 a3 := int(p.To.Class) 1199 if a3 == 0 { 1200 a3 = aclass(ctxt, &p.To) + 1 1201 p.To.Class = int8(a3) 1202 } 1203 1204 a3-- 1205 a2 := C_NONE 1206 if p.Reg != 0 { 1207 a2 = C_REG 1208 } 1209 r := p.As & obj.AMask 1210 o := oprange[r].start 1211 if o == nil { 1212 o = oprange[r].stop /* just generate an error */ 1213 } 1214 1215 if false { /*debug['O']*/ 1216 fmt.Printf("oplook %v %v %v %v\n", obj.Aconv(int(p.As)), DRconv(a1), DRconv(a2), DRconv(a3)) 1217 fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type) 1218 } 1219 1220 e := oprange[r].stop 1221 c1 := xcmp[a1][:] 1222 c3 := xcmp[a3][:] 1223 for ; -cap(o) < -cap(e); o = o[1:] { 1224 if int(o[0].a2) == a2 { 1225 if c1[o[0].a1] != 0 { 1226 if c3[o[0].a3] != 0 { 1227 p.Optab = uint16((-cap(o) + cap(optab)) + 1) 1228 return &o[0] 1229 } 1230 } 1231 } 1232 } 1233 1234 ctxt.Diag("illegal combination %v; %v %v %v, %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.To.Type) 1235 ctxt.Diag("from %d %d to %d %d\n", p.From.Type, p.From.Name, p.To.Type, p.To.Name) 1236 prasm(p) 1237 if o == nil { 1238 o = optab 1239 } 1240 return &o[0] 1241 } 1242 1243 func cmp(a int, b int) bool { 1244 if a == b { 1245 return true 1246 } 1247 switch a { 1248 case C_LCON: 1249 if b == C_RCON || b == C_NCON { 1250 return true 1251 } 1252 1253 case C_LACON: 1254 if b == C_RACON { 1255 return true 1256 } 1257 1258 case C_LFCON: 1259 if b == C_ZFCON || b == C_SFCON { 1260 return true 1261 } 1262 1263 case C_HFAUTO: 1264 return b == C_HAUTO || b == C_FAUTO 1265 1266 case C_FAUTO, C_HAUTO: 1267 return b == C_HFAUTO 1268 1269 case C_SAUTO: 1270 return cmp(C_HFAUTO, b) 1271 1272 case C_LAUTO: 1273 return cmp(C_SAUTO, b) 1274 1275 case C_HFOREG: 1276 return b == C_HOREG || b == C_FOREG 1277 1278 case C_FOREG, C_HOREG: 1279 return b == C_HFOREG 1280 1281 case C_SROREG: 1282 return cmp(C_SOREG, b) || cmp(C_ROREG, b) 1283 1284 case C_SOREG, C_ROREG: 1285 return b == C_SROREG || cmp(C_HFOREG, b) 1286 1287 case C_LOREG: 1288 return cmp(C_SROREG, b) 1289 1290 case C_LBRA: 1291 if b == C_SBRA { 1292 return true 1293 } 1294 1295 case C_HREG: 1296 return cmp(C_SP, b) || cmp(C_PC, b) 1297 } 1298 1299 return false 1300 } 1301 1302 type ocmp []Optab 1303 1304 func (x ocmp) Len() int { 1305 return len(x) 1306 } 1307 1308 func (x ocmp) Swap(i, j int) { 1309 x[i], x[j] = x[j], x[i] 1310 } 1311 1312 func (x ocmp) Less(i, j int) bool { 1313 p1 := &x[i] 1314 p2 := &x[j] 1315 n := int(p1.as) - int(p2.as) 1316 if n != 0 { 1317 return n < 0 1318 } 1319 n = int(p1.a1) - int(p2.a1) 1320 if n != 0 { 1321 return n < 0 1322 } 1323 n = int(p1.a2) - int(p2.a2) 1324 if n != 0 { 1325 return n < 0 1326 } 1327 n = int(p1.a3) - int(p2.a3) 1328 if n != 0 { 1329 return n < 0 1330 } 1331 return false 1332 } 1333 1334 func opset(a, b0 uint16) { 1335 oprange[a&obj.AMask] = oprange[b0] 1336 } 1337 1338 func buildop(ctxt *obj.Link) { 1339 var n int 1340 1341 for i := 0; i < C_GOK; i++ { 1342 for n = 0; n < C_GOK; n++ { 1343 if cmp(n, i) { 1344 xcmp[i][n] = 1 1345 } 1346 } 1347 } 1348 for n = 0; optab[n].as != obj.AXXX; n++ { 1349 if optab[n].flag&LPCREL != 0 { 1350 if ctxt.Flag_shared != 0 { 1351 optab[n].size += int8(optab[n].pcrelsiz) 1352 } else { 1353 optab[n].flag &^= LPCREL 1354 } 1355 } 1356 } 1357 1358 sort.Sort(ocmp(optab[:n])) 1359 for i := 0; i < n; i++ { 1360 r := optab[i].as 1361 r0 := r & obj.AMask 1362 oprange[r0].start = optab[i:] 1363 for optab[i].as == r { 1364 i++ 1365 } 1366 oprange[r0].stop = optab[i:] 1367 i-- 1368 1369 switch r { 1370 default: 1371 ctxt.Diag("unknown op in build: %v", obj.Aconv(int(r))) 1372 log.Fatalf("bad code") 1373 1374 case AADD: 1375 opset(AAND, r0) 1376 opset(AEOR, r0) 1377 opset(ASUB, r0) 1378 opset(ARSB, r0) 1379 opset(AADC, r0) 1380 opset(ASBC, r0) 1381 opset(ARSC, r0) 1382 opset(AORR, r0) 1383 opset(ABIC, r0) 1384 1385 case ACMP: 1386 opset(ATEQ, r0) 1387 opset(ACMN, r0) 1388 1389 case AMVN: 1390 break 1391 1392 case ABEQ: 1393 opset(ABNE, r0) 1394 opset(ABCS, r0) 1395 opset(ABHS, r0) 1396 opset(ABCC, r0) 1397 opset(ABLO, r0) 1398 opset(ABMI, r0) 1399 opset(ABPL, r0) 1400 opset(ABVS, r0) 1401 opset(ABVC, r0) 1402 opset(ABHI, r0) 1403 opset(ABLS, r0) 1404 opset(ABGE, r0) 1405 opset(ABLT, r0) 1406 opset(ABGT, r0) 1407 opset(ABLE, r0) 1408 1409 case ASLL: 1410 opset(ASRL, r0) 1411 opset(ASRA, r0) 1412 1413 case AMUL: 1414 opset(AMULU, r0) 1415 1416 case ADIV: 1417 opset(AMOD, r0) 1418 opset(AMODU, r0) 1419 opset(ADIVU, r0) 1420 1421 case AMOVW, 1422 AMOVB, 1423 AMOVBS, 1424 AMOVBU, 1425 AMOVH, 1426 AMOVHS, 1427 AMOVHU: 1428 break 1429 1430 case ASWPW: 1431 opset(ASWPBU, r0) 1432 1433 case AB, 1434 ABL, 1435 ABX, 1436 ABXRET, 1437 obj.ADUFFZERO, 1438 obj.ADUFFCOPY, 1439 ASWI, 1440 AWORD, 1441 AMOVM, 1442 ARFE, 1443 obj.ATEXT, 1444 obj.AUSEFIELD, 1445 ACASE, 1446 ABCASE, 1447 obj.ATYPE: 1448 break 1449 1450 case AADDF: 1451 opset(AADDD, r0) 1452 opset(ASUBF, r0) 1453 opset(ASUBD, r0) 1454 opset(AMULF, r0) 1455 opset(AMULD, r0) 1456 opset(ADIVF, r0) 1457 opset(ADIVD, r0) 1458 opset(ASQRTF, r0) 1459 opset(ASQRTD, r0) 1460 opset(AMOVFD, r0) 1461 opset(AMOVDF, r0) 1462 opset(AABSF, r0) 1463 opset(AABSD, r0) 1464 1465 case ACMPF: 1466 opset(ACMPD, r0) 1467 1468 case AMOVF: 1469 opset(AMOVD, r0) 1470 1471 case AMOVFW: 1472 opset(AMOVDW, r0) 1473 1474 case AMOVWF: 1475 opset(AMOVWD, r0) 1476 1477 case AMULL: 1478 opset(AMULAL, r0) 1479 opset(AMULLU, r0) 1480 opset(AMULALU, r0) 1481 1482 case AMULWT: 1483 opset(AMULWB, r0) 1484 1485 case AMULAWT: 1486 opset(AMULAWB, r0) 1487 1488 case AMULA, 1489 ALDREX, 1490 ASTREX, 1491 ALDREXD, 1492 ASTREXD, 1493 ATST, 1494 APLD, 1495 obj.AUNDEF, 1496 ACLZ, 1497 obj.AFUNCDATA, 1498 obj.APCDATA, 1499 obj.ANOP, 1500 ADATABUNDLE, 1501 ADATABUNDLEEND: 1502 break 1503 } 1504 } 1505 } 1506 1507 func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { 1508 ctxt.Printp = p 1509 o1 := uint32(0) 1510 o2 := uint32(0) 1511 o3 := uint32(0) 1512 o4 := uint32(0) 1513 o5 := uint32(0) 1514 o6 := uint32(0) 1515 ctxt.Armsize += int32(o.size) 1516 if false { /*debug['P']*/ 1517 fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_) 1518 } 1519 switch o.type_ { 1520 default: 1521 ctxt.Diag("unknown asm %d", o.type_) 1522 prasm(p) 1523 1524 case 0: /* pseudo ops */ 1525 if false { /*debug['G']*/ 1526 fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name) 1527 } 1528 1529 case 1: /* op R,[R],R */ 1530 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 1531 1532 rf := int(p.From.Reg) 1533 rt := int(p.To.Reg) 1534 r := int(p.Reg) 1535 if p.To.Type == obj.TYPE_NONE { 1536 rt = 0 1537 } 1538 if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN { 1539 r = 0 1540 } else if r == 0 { 1541 r = rt 1542 } 1543 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1544 1545 case 2: /* movbu $I,[R],R */ 1546 aclass(ctxt, &p.From) 1547 1548 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 1549 o1 |= uint32(immrot(uint32(ctxt.Instoffset))) 1550 rt := int(p.To.Reg) 1551 r := int(p.Reg) 1552 if p.To.Type == obj.TYPE_NONE { 1553 rt = 0 1554 } 1555 if p.As == AMOVW || p.As == AMVN { 1556 r = 0 1557 } else if r == 0 { 1558 r = rt 1559 } 1560 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1561 1562 case 3: /* add R<<[IR],[R],R */ 1563 o1 = mov(ctxt, p) 1564 1565 case 4: /* add $I,[R],R */ 1566 aclass(ctxt, &p.From) 1567 1568 o1 = oprrr(ctxt, AADD, int(p.Scond)) 1569 o1 |= uint32(immrot(uint32(ctxt.Instoffset))) 1570 r := int(p.From.Reg) 1571 if r == 0 { 1572 r = int(o.param) 1573 } 1574 o1 |= (uint32(r) & 15) << 16 1575 o1 |= (uint32(p.To.Reg) & 15) << 12 1576 1577 case 5: /* bra s */ 1578 o1 = opbra(ctxt, int(p.As), int(p.Scond)) 1579 1580 v := int32(-8) 1581 if p.To.Sym != nil { 1582 rel := obj.Addrel(ctxt.Cursym) 1583 rel.Off = int32(ctxt.Pc) 1584 rel.Siz = 4 1585 rel.Sym = p.To.Sym 1586 v += int32(p.To.Offset) 1587 rel.Add = int64(o1) | (int64(v)>>2)&0xffffff 1588 rel.Type = obj.R_CALLARM 1589 break 1590 } 1591 1592 if p.Pcond != nil { 1593 v = int32((p.Pcond.Pc - ctxt.Pc) - 8) 1594 } 1595 o1 |= (uint32(v) >> 2) & 0xffffff 1596 1597 case 6: /* b ,O(R) -> add $O,R,PC */ 1598 aclass(ctxt, &p.To) 1599 1600 o1 = oprrr(ctxt, AADD, int(p.Scond)) 1601 o1 |= uint32(immrot(uint32(ctxt.Instoffset))) 1602 o1 |= (uint32(p.To.Reg) & 15) << 16 1603 o1 |= (REGPC & 15) << 12 1604 1605 case 7: /* bl (R) -> blx R */ 1606 aclass(ctxt, &p.To) 1607 1608 if ctxt.Instoffset != 0 { 1609 ctxt.Diag("%v: doesn't support BL offset(REG) where offset != 0", p) 1610 } 1611 o1 = oprrr(ctxt, ABL, int(p.Scond)) 1612 o1 |= (uint32(p.To.Reg) & 15) << 0 1613 rel := obj.Addrel(ctxt.Cursym) 1614 rel.Off = int32(ctxt.Pc) 1615 rel.Siz = 0 1616 rel.Type = obj.R_CALLIND 1617 1618 case 8: /* sll $c,[R],R -> mov (R<<$c),R */ 1619 aclass(ctxt, &p.From) 1620 1621 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 1622 r := int(p.Reg) 1623 if r == 0 { 1624 r = int(p.To.Reg) 1625 } 1626 o1 |= (uint32(r) & 15) << 0 1627 o1 |= uint32((ctxt.Instoffset & 31) << 7) 1628 o1 |= (uint32(p.To.Reg) & 15) << 12 1629 1630 case 9: /* sll R,[R],R -> mov (R<<R),R */ 1631 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 1632 1633 r := int(p.Reg) 1634 if r == 0 { 1635 r = int(p.To.Reg) 1636 } 1637 o1 |= (uint32(r) & 15) << 0 1638 o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4 1639 o1 |= (uint32(p.To.Reg) & 15) << 12 1640 1641 case 10: /* swi [$con] */ 1642 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 1643 1644 if p.To.Type != obj.TYPE_NONE { 1645 aclass(ctxt, &p.To) 1646 o1 |= uint32(ctxt.Instoffset & 0xffffff) 1647 } 1648 1649 case 11: /* word */ 1650 aclass(ctxt, &p.To) 1651 1652 o1 = uint32(ctxt.Instoffset) 1653 if p.To.Sym != nil { 1654 // This case happens with words generated 1655 // in the PC stream as part of the literal pool. 1656 rel := obj.Addrel(ctxt.Cursym) 1657 1658 rel.Off = int32(ctxt.Pc) 1659 rel.Siz = 4 1660 rel.Sym = p.To.Sym 1661 rel.Add = p.To.Offset 1662 1663 // runtime.tlsg is special. 1664 // Its "address" is the offset from the TLS thread pointer 1665 // to the thread-local g and m pointers. 1666 // Emit a TLS relocation instead of a standard one if its 1667 // type is not explicitly set by runtime. This assumes that 1668 // all references to runtime.tlsg should be accompanied with 1669 // its type declaration if necessary. 1670 if rel.Sym == ctxt.Tlsg && ctxt.Tlsg.Type == 0 { 1671 rel.Type = obj.R_TLS 1672 if ctxt.Flag_shared != 0 { 1673 rel.Add += ctxt.Pc - p.Rel.Pc - 8 - int64(rel.Siz) 1674 } 1675 } else if ctxt.Flag_shared != 0 { 1676 rel.Type = obj.R_PCREL 1677 rel.Add += ctxt.Pc - p.Rel.Pc - 8 1678 } else { 1679 rel.Type = obj.R_ADDR 1680 } 1681 o1 = 0 1682 } 1683 1684 case 12: /* movw $lcon, reg */ 1685 o1 = omvl(ctxt, p, &p.From, int(p.To.Reg)) 1686 1687 if o.flag&LPCREL != 0 { 1688 o2 = oprrr(ctxt, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12 1689 } 1690 1691 case 13: /* op $lcon, [R], R */ 1692 o1 = omvl(ctxt, p, &p.From, REGTMP) 1693 1694 if o1 == 0 { 1695 break 1696 } 1697 o2 = oprrr(ctxt, int(p.As), int(p.Scond)) 1698 o2 |= REGTMP & 15 1699 r := int(p.Reg) 1700 if p.As == AMOVW || p.As == AMVN { 1701 r = 0 1702 } else if r == 0 { 1703 r = int(p.To.Reg) 1704 } 1705 o2 |= (uint32(r) & 15) << 16 1706 if p.To.Type != obj.TYPE_NONE { 1707 o2 |= (uint32(p.To.Reg) & 15) << 12 1708 } 1709 1710 case 14: /* movb/movbu/movh/movhu R,R */ 1711 o1 = oprrr(ctxt, ASLL, int(p.Scond)) 1712 1713 if p.As == AMOVBU || p.As == AMOVHU { 1714 o2 = oprrr(ctxt, ASRL, int(p.Scond)) 1715 } else { 1716 o2 = oprrr(ctxt, ASRA, int(p.Scond)) 1717 } 1718 1719 r := int(p.To.Reg) 1720 o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12 1721 o2 |= uint32(r)&15 | (uint32(r)&15)<<12 1722 if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU { 1723 o1 |= 24 << 7 1724 o2 |= 24 << 7 1725 } else { 1726 o1 |= 16 << 7 1727 o2 |= 16 << 7 1728 } 1729 1730 case 15: /* mul r,[r,]r */ 1731 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 1732 1733 rf := int(p.From.Reg) 1734 rt := int(p.To.Reg) 1735 r := int(p.Reg) 1736 if r == 0 { 1737 r = rt 1738 } 1739 if rt == r { 1740 r = rf 1741 rf = rt 1742 } 1743 1744 if false { 1745 if rt == r || rf == REGPC&15 || r == REGPC&15 || rt == REGPC&15 { 1746 ctxt.Diag("bad registers in MUL") 1747 prasm(p) 1748 } 1749 } 1750 1751 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 1752 1753 case 16: /* div r,[r,]r */ 1754 o1 = 0xf << 28 1755 1756 o2 = 0 1757 1758 case 17: 1759 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 1760 rf := int(p.From.Reg) 1761 rt := int(p.To.Reg) 1762 rt2 := int(p.To.Offset) 1763 r := int(p.Reg) 1764 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12 1765 1766 case 20: /* mov/movb/movbu R,O(R) */ 1767 aclass(ctxt, &p.To) 1768 1769 r := int(p.To.Reg) 1770 if r == 0 { 1771 r = int(o.param) 1772 } 1773 o1 = osr(ctxt, int(p.As), int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond)) 1774 1775 case 21: /* mov/movbu O(R),R -> lr */ 1776 aclass(ctxt, &p.From) 1777 1778 r := int(p.From.Reg) 1779 if r == 0 { 1780 r = int(o.param) 1781 } 1782 o1 = olr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond)) 1783 if p.As != AMOVW { 1784 o1 |= 1 << 22 1785 } 1786 1787 case 30: /* mov/movb/movbu R,L(R) */ 1788 o1 = omvl(ctxt, p, &p.To, REGTMP) 1789 1790 if o1 == 0 { 1791 break 1792 } 1793 r := int(p.To.Reg) 1794 if r == 0 { 1795 r = int(o.param) 1796 } 1797 o2 = osrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond)) 1798 if p.As != AMOVW { 1799 o2 |= 1 << 22 1800 } 1801 1802 case 31: /* mov/movbu L(R),R -> lr[b] */ 1803 o1 = omvl(ctxt, p, &p.From, REGTMP) 1804 1805 if o1 == 0 { 1806 break 1807 } 1808 r := int(p.From.Reg) 1809 if r == 0 { 1810 r = int(o.param) 1811 } 1812 o2 = olrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond)) 1813 if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { 1814 o2 |= 1 << 22 1815 } 1816 1817 case 34: /* mov $lacon,R */ 1818 o1 = omvl(ctxt, p, &p.From, REGTMP) 1819 1820 if o1 == 0 { 1821 break 1822 } 1823 1824 o2 = oprrr(ctxt, AADD, int(p.Scond)) 1825 o2 |= REGTMP & 15 1826 r := int(p.From.Reg) 1827 if r == 0 { 1828 r = int(o.param) 1829 } 1830 o2 |= (uint32(r) & 15) << 16 1831 if p.To.Type != obj.TYPE_NONE { 1832 o2 |= (uint32(p.To.Reg) & 15) << 12 1833 } 1834 1835 case 35: /* mov PSR,R */ 1836 o1 = 2<<23 | 0xf<<16 | 0<<0 1837 1838 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1839 o1 |= (uint32(p.From.Reg) & 1) << 22 1840 o1 |= (uint32(p.To.Reg) & 15) << 12 1841 1842 case 36: /* mov R,PSR */ 1843 o1 = 2<<23 | 0x29f<<12 | 0<<4 1844 1845 if p.Scond&C_FBIT != 0 { 1846 o1 ^= 0x010 << 12 1847 } 1848 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1849 o1 |= (uint32(p.To.Reg) & 1) << 22 1850 o1 |= (uint32(p.From.Reg) & 15) << 0 1851 1852 case 37: /* mov $con,PSR */ 1853 aclass(ctxt, &p.From) 1854 1855 o1 = 2<<23 | 0x29f<<12 | 0<<4 1856 if p.Scond&C_FBIT != 0 { 1857 o1 ^= 0x010 << 12 1858 } 1859 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1860 o1 |= uint32(immrot(uint32(ctxt.Instoffset))) 1861 o1 |= (uint32(p.To.Reg) & 1) << 22 1862 o1 |= (uint32(p.From.Reg) & 15) << 0 1863 1864 case 38, 39: 1865 switch o.type_ { 1866 case 38: /* movm $con,oreg -> stm */ 1867 o1 = 0x4 << 25 1868 1869 o1 |= uint32(p.From.Offset & 0xffff) 1870 o1 |= (uint32(p.To.Reg) & 15) << 16 1871 aclass(ctxt, &p.To) 1872 1873 case 39: /* movm oreg,$con -> ldm */ 1874 o1 = 0x4<<25 | 1<<20 1875 1876 o1 |= uint32(p.To.Offset & 0xffff) 1877 o1 |= (uint32(p.From.Reg) & 15) << 16 1878 aclass(ctxt, &p.From) 1879 } 1880 1881 if ctxt.Instoffset != 0 { 1882 ctxt.Diag("offset must be zero in MOVM; %v", p) 1883 } 1884 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1885 if p.Scond&C_PBIT != 0 { 1886 o1 |= 1 << 24 1887 } 1888 if p.Scond&C_UBIT != 0 { 1889 o1 |= 1 << 23 1890 } 1891 if p.Scond&C_SBIT != 0 { 1892 o1 |= 1 << 22 1893 } 1894 if p.Scond&C_WBIT != 0 { 1895 o1 |= 1 << 21 1896 } 1897 1898 case 40: /* swp oreg,reg,reg */ 1899 aclass(ctxt, &p.From) 1900 1901 if ctxt.Instoffset != 0 { 1902 ctxt.Diag("offset must be zero in SWP") 1903 } 1904 o1 = 0x2<<23 | 0x9<<4 1905 if p.As != ASWPW { 1906 o1 |= 1 << 22 1907 } 1908 o1 |= (uint32(p.From.Reg) & 15) << 16 1909 o1 |= (uint32(p.Reg) & 15) << 0 1910 o1 |= (uint32(p.To.Reg) & 15) << 12 1911 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 1912 1913 case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ 1914 o1 = 0xe8fd8000 1915 1916 case 50: /* floating point store */ 1917 v := regoff(ctxt, &p.To) 1918 1919 r := int(p.To.Reg) 1920 if r == 0 { 1921 r = int(o.param) 1922 } 1923 o1 = ofsr(ctxt, int(p.As), int(p.From.Reg), v, r, int(p.Scond), p) 1924 1925 case 51: /* floating point load */ 1926 v := regoff(ctxt, &p.From) 1927 1928 r := int(p.From.Reg) 1929 if r == 0 { 1930 r = int(o.param) 1931 } 1932 o1 = ofsr(ctxt, int(p.As), int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20 1933 1934 case 52: /* floating point store, int32 offset UGLY */ 1935 o1 = omvl(ctxt, p, &p.To, REGTMP) 1936 1937 if o1 == 0 { 1938 break 1939 } 1940 r := int(p.To.Reg) 1941 if r == 0 { 1942 r = int(o.param) 1943 } 1944 o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 1945 o3 = ofsr(ctxt, int(p.As), int(p.From.Reg), 0, REGTMP, int(p.Scond), p) 1946 1947 case 53: /* floating point load, int32 offset UGLY */ 1948 o1 = omvl(ctxt, p, &p.From, REGTMP) 1949 1950 if o1 == 0 { 1951 break 1952 } 1953 r := int(p.From.Reg) 1954 if r == 0 { 1955 r = int(o.param) 1956 } 1957 o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0 1958 o3 = ofsr(ctxt, int(p.As), int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 1959 1960 case 54: /* floating point arith */ 1961 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 1962 1963 rf := int(p.From.Reg) 1964 rt := int(p.To.Reg) 1965 r := int(p.Reg) 1966 if r == 0 { 1967 r = rt 1968 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 { 1969 r = 0 1970 } 1971 } 1972 1973 o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1974 1975 case 56: /* move to FP[CS]R */ 1976 o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4 1977 1978 o1 |= ((uint32(p.To.Reg)&1)+1)<<21 | (uint32(p.From.Reg)&15)<<12 1979 1980 case 57: /* move from FP[CS]R */ 1981 o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4 1982 1983 o1 |= ((uint32(p.From.Reg)&1)+1)<<21 | (uint32(p.To.Reg)&15)<<12 | 1<<20 1984 1985 case 58: /* movbu R,R */ 1986 o1 = oprrr(ctxt, AAND, int(p.Scond)) 1987 1988 o1 |= uint32(immrot(0xff)) 1989 rt := int(p.To.Reg) 1990 r := int(p.From.Reg) 1991 if p.To.Type == obj.TYPE_NONE { 1992 rt = 0 1993 } 1994 if r == 0 { 1995 r = rt 1996 } 1997 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 1998 1999 case 59: /* movw/bu R<<I(R),R -> ldr indexed */ 2000 if p.From.Reg == 0 { 2001 if p.As != AMOVW { 2002 ctxt.Diag("byte MOV from shifter operand") 2003 } 2004 o1 = mov(ctxt, p) 2005 break 2006 } 2007 2008 if p.From.Offset&(1<<4) != 0 { 2009 ctxt.Diag("bad shift in LDR") 2010 } 2011 o1 = olrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) 2012 if p.As == AMOVBU { 2013 o1 |= 1 << 22 2014 } 2015 2016 case 60: /* movb R(R),R -> ldrsb indexed */ 2017 if p.From.Reg == 0 { 2018 ctxt.Diag("byte MOV from shifter operand") 2019 o1 = mov(ctxt, p) 2020 break 2021 } 2022 2023 if p.From.Offset&(^0xf) != 0 { 2024 ctxt.Diag("bad shift in LDRSB") 2025 } 2026 o1 = olhrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond)) 2027 o1 ^= 1<<5 | 1<<6 2028 2029 case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ 2030 if p.To.Reg == 0 { 2031 ctxt.Diag("MOV to shifter operand") 2032 } 2033 o1 = osrr(ctxt, int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond)) 2034 if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU { 2035 o1 |= 1 << 22 2036 } 2037 2038 case 62: /* case R -> movw R<<2(PC),PC */ 2039 if o.flag&LPCREL != 0 { 2040 o1 = oprrr(ctxt, AADD, int(p.Scond)) | uint32(immrot(1)) | (uint32(p.From.Reg)&15)<<16 | (REGTMP&15)<<12 2041 o2 = olrr(ctxt, REGTMP&15, REGPC, REGTMP, int(p.Scond)) 2042 o2 |= 2 << 7 2043 o3 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGPC&15)<<12 2044 } else { 2045 o1 = olrr(ctxt, int(p.From.Reg)&15, REGPC, REGPC, int(p.Scond)) 2046 o1 |= 2 << 7 2047 } 2048 2049 case 63: /* bcase */ 2050 if p.Pcond != nil { 2051 rel := obj.Addrel(ctxt.Cursym) 2052 rel.Off = int32(ctxt.Pc) 2053 rel.Siz = 4 2054 if p.To.Sym != nil && p.To.Sym.Type != 0 { 2055 rel.Sym = p.To.Sym 2056 rel.Add = p.To.Offset 2057 } else { 2058 rel.Sym = ctxt.Cursym 2059 rel.Add = p.Pcond.Pc 2060 } 2061 2062 if o.flag&LPCREL != 0 { 2063 rel.Type = obj.R_PCREL 2064 rel.Add += ctxt.Pc - p.Rel.Pc - 16 + int64(rel.Siz) 2065 } else { 2066 rel.Type = obj.R_ADDR 2067 } 2068 o1 = 0 2069 } 2070 2071 /* reloc ops */ 2072 case 64: /* mov/movb/movbu R,addr */ 2073 o1 = omvl(ctxt, p, &p.To, REGTMP) 2074 2075 if o1 == 0 { 2076 break 2077 } 2078 o2 = osr(ctxt, int(p.As), int(p.From.Reg), 0, REGTMP, int(p.Scond)) 2079 if o.flag&LPCREL != 0 { 2080 o3 = o2 2081 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2082 } 2083 2084 case 65: /* mov/movbu addr,R */ 2085 o1 = omvl(ctxt, p, &p.From, REGTMP) 2086 2087 if o1 == 0 { 2088 break 2089 } 2090 o2 = olr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond)) 2091 if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB { 2092 o2 |= 1 << 22 2093 } 2094 if o.flag&LPCREL != 0 { 2095 o3 = o2 2096 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2097 } 2098 2099 case 68: /* floating point store -> ADDR */ 2100 o1 = omvl(ctxt, p, &p.To, REGTMP) 2101 2102 if o1 == 0 { 2103 break 2104 } 2105 o2 = ofsr(ctxt, int(p.As), int(p.From.Reg), 0, REGTMP, int(p.Scond), p) 2106 if o.flag&LPCREL != 0 { 2107 o3 = o2 2108 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2109 } 2110 2111 case 69: /* floating point load <- ADDR */ 2112 o1 = omvl(ctxt, p, &p.From, REGTMP) 2113 2114 if o1 == 0 { 2115 break 2116 } 2117 o2 = ofsr(ctxt, int(p.As), int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20 2118 if o.flag&LPCREL != 0 { 2119 o3 = o2 2120 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2121 } 2122 2123 /* ArmV4 ops: */ 2124 case 70: /* movh/movhu R,O(R) -> strh */ 2125 aclass(ctxt, &p.To) 2126 2127 r := int(p.To.Reg) 2128 if r == 0 { 2129 r = int(o.param) 2130 } 2131 o1 = oshr(ctxt, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond)) 2132 2133 case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ 2134 aclass(ctxt, &p.From) 2135 2136 r := int(p.From.Reg) 2137 if r == 0 { 2138 r = int(o.param) 2139 } 2140 o1 = olhr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond)) 2141 if p.As == AMOVB || p.As == AMOVBS { 2142 o1 ^= 1<<5 | 1<<6 2143 } else if p.As == AMOVH || p.As == AMOVHS { 2144 o1 ^= (1 << 6) 2145 } 2146 2147 case 72: /* movh/movhu R,L(R) -> strh */ 2148 o1 = omvl(ctxt, p, &p.To, REGTMP) 2149 2150 if o1 == 0 { 2151 break 2152 } 2153 r := int(p.To.Reg) 2154 if r == 0 { 2155 r = int(o.param) 2156 } 2157 o2 = oshrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond)) 2158 2159 case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ 2160 o1 = omvl(ctxt, p, &p.From, REGTMP) 2161 2162 if o1 == 0 { 2163 break 2164 } 2165 r := int(p.From.Reg) 2166 if r == 0 { 2167 r = int(o.param) 2168 } 2169 o2 = olhrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond)) 2170 if p.As == AMOVB || p.As == AMOVBS { 2171 o2 ^= 1<<5 | 1<<6 2172 } else if p.As == AMOVH || p.As == AMOVHS { 2173 o2 ^= (1 << 6) 2174 } 2175 2176 case 74: /* bx $I */ 2177 ctxt.Diag("ABX $I") 2178 2179 case 75: /* bx O(R) */ 2180 aclass(ctxt, &p.To) 2181 2182 if ctxt.Instoffset != 0 { 2183 ctxt.Diag("non-zero offset in ABX") 2184 } 2185 2186 /* 2187 o1 = oprrr(ctxt, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12); // mov PC, LR 2188 o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0); // BX R 2189 */ 2190 // p->to.reg may be REGLINK 2191 o1 = oprrr(ctxt, AADD, int(p.Scond)) 2192 2193 o1 |= uint32(immrot(uint32(ctxt.Instoffset))) 2194 o1 |= (uint32(p.To.Reg) & 15) << 16 2195 o1 |= (REGTMP & 15) << 12 2196 o2 = oprrr(ctxt, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR 2197 o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15 // BX Rtmp 2198 2199 case 76: /* bx O(R) when returning from fn*/ 2200 ctxt.Diag("ABXRET") 2201 2202 case 77: /* ldrex oreg,reg */ 2203 aclass(ctxt, &p.From) 2204 2205 if ctxt.Instoffset != 0 { 2206 ctxt.Diag("offset must be zero in LDREX") 2207 } 2208 o1 = 0x19<<20 | 0xf9f 2209 o1 |= (uint32(p.From.Reg) & 15) << 16 2210 o1 |= (uint32(p.To.Reg) & 15) << 12 2211 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2212 2213 case 78: /* strex reg,oreg,reg */ 2214 aclass(ctxt, &p.From) 2215 2216 if ctxt.Instoffset != 0 { 2217 ctxt.Diag("offset must be zero in STREX") 2218 } 2219 o1 = 0x18<<20 | 0xf90 2220 o1 |= (uint32(p.From.Reg) & 15) << 16 2221 o1 |= (uint32(p.Reg) & 15) << 0 2222 o1 |= (uint32(p.To.Reg) & 15) << 12 2223 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2224 2225 case 80: /* fmov zfcon,freg */ 2226 if p.As == AMOVD { 2227 o1 = 0xeeb00b00 // VMOV imm 64 2228 o2 = oprrr(ctxt, ASUBD, int(p.Scond)) 2229 } else { 2230 o1 = 0x0eb00a00 // VMOV imm 32 2231 o2 = oprrr(ctxt, ASUBF, int(p.Scond)) 2232 } 2233 2234 v := int32(0x70) // 1.0 2235 r := (int(p.To.Reg) & 15) << 0 2236 2237 // movf $1.0, r 2238 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2239 2240 o1 |= (uint32(r) & 15) << 12 2241 o1 |= (uint32(v) & 0xf) << 0 2242 o1 |= (uint32(v) & 0xf0) << 12 2243 2244 // subf r,r,r 2245 o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12 2246 2247 case 81: /* fmov sfcon,freg */ 2248 o1 = 0x0eb00a00 // VMOV imm 32 2249 if p.As == AMOVD { 2250 o1 = 0xeeb00b00 // VMOV imm 64 2251 } 2252 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2253 o1 |= (uint32(p.To.Reg) & 15) << 12 2254 v := int32(chipfloat5(ctxt, p.From.Val.(float64))) 2255 o1 |= (uint32(v) & 0xf) << 0 2256 o1 |= (uint32(v) & 0xf0) << 12 2257 2258 case 82: /* fcmp freg,freg, */ 2259 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2260 2261 o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0 2262 o2 = 0x0ef1fa10 // VMRS R15 2263 o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2264 2265 case 83: /* fcmp freg,, */ 2266 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2267 2268 o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16 2269 o2 = 0x0ef1fa10 // VMRS R15 2270 o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2271 2272 case 84: /* movfw freg,freg - truncate float-to-fix */ 2273 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2274 2275 o1 |= (uint32(p.From.Reg) & 15) << 0 2276 o1 |= (uint32(p.To.Reg) & 15) << 12 2277 2278 case 85: /* movwf freg,freg - fix-to-float */ 2279 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2280 2281 o1 |= (uint32(p.From.Reg) & 15) << 0 2282 o1 |= (uint32(p.To.Reg) & 15) << 12 2283 2284 // macro for movfw freg,FTMP; movw FTMP,reg 2285 case 86: /* movfw freg,reg - truncate float-to-fix */ 2286 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2287 2288 o1 |= (uint32(p.From.Reg) & 15) << 0 2289 o1 |= (FREGTMP & 15) << 12 2290 o2 = oprrr(ctxt, AMOVFW+ALAST, int(p.Scond)) 2291 o2 |= (FREGTMP & 15) << 16 2292 o2 |= (uint32(p.To.Reg) & 15) << 12 2293 2294 // macro for movw reg,FTMP; movwf FTMP,freg 2295 case 87: /* movwf reg,freg - fix-to-float */ 2296 o1 = oprrr(ctxt, AMOVWF+ALAST, int(p.Scond)) 2297 2298 o1 |= (uint32(p.From.Reg) & 15) << 12 2299 o1 |= (FREGTMP & 15) << 16 2300 o2 = oprrr(ctxt, int(p.As), int(p.Scond)) 2301 o2 |= (FREGTMP & 15) << 0 2302 o2 |= (uint32(p.To.Reg) & 15) << 12 2303 2304 case 88: /* movw reg,freg */ 2305 o1 = oprrr(ctxt, AMOVWF+ALAST, int(p.Scond)) 2306 2307 o1 |= (uint32(p.From.Reg) & 15) << 12 2308 o1 |= (uint32(p.To.Reg) & 15) << 16 2309 2310 case 89: /* movw freg,reg */ 2311 o1 = oprrr(ctxt, AMOVFW+ALAST, int(p.Scond)) 2312 2313 o1 |= (uint32(p.From.Reg) & 15) << 16 2314 o1 |= (uint32(p.To.Reg) & 15) << 12 2315 2316 case 90: /* tst reg */ 2317 o1 = oprrr(ctxt, ACMP+ALAST, int(p.Scond)) 2318 2319 o1 |= (uint32(p.From.Reg) & 15) << 16 2320 2321 case 91: /* ldrexd oreg,reg */ 2322 aclass(ctxt, &p.From) 2323 2324 if ctxt.Instoffset != 0 { 2325 ctxt.Diag("offset must be zero in LDREX") 2326 } 2327 o1 = 0x1b<<20 | 0xf9f 2328 o1 |= (uint32(p.From.Reg) & 15) << 16 2329 o1 |= (uint32(p.To.Reg) & 15) << 12 2330 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2331 2332 case 92: /* strexd reg,oreg,reg */ 2333 aclass(ctxt, &p.From) 2334 2335 if ctxt.Instoffset != 0 { 2336 ctxt.Diag("offset must be zero in STREX") 2337 } 2338 o1 = 0x1a<<20 | 0xf90 2339 o1 |= (uint32(p.From.Reg) & 15) << 16 2340 o1 |= (uint32(p.Reg) & 15) << 0 2341 o1 |= (uint32(p.To.Reg) & 15) << 12 2342 o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28 2343 2344 case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ 2345 o1 = omvl(ctxt, p, &p.From, REGTMP) 2346 2347 if o1 == 0 { 2348 break 2349 } 2350 o2 = olhr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond)) 2351 if p.As == AMOVB || p.As == AMOVBS { 2352 o2 ^= 1<<5 | 1<<6 2353 } else if p.As == AMOVH || p.As == AMOVHS { 2354 o2 ^= (1 << 6) 2355 } 2356 if o.flag&LPCREL != 0 { 2357 o3 = o2 2358 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2359 } 2360 2361 case 94: /* movh/movhu R,addr -> strh */ 2362 o1 = omvl(ctxt, p, &p.To, REGTMP) 2363 2364 if o1 == 0 { 2365 break 2366 } 2367 o2 = oshr(ctxt, int(p.From.Reg), 0, REGTMP, int(p.Scond)) 2368 if o.flag&LPCREL != 0 { 2369 o3 = o2 2370 o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12 2371 } 2372 2373 case 95: /* PLD off(reg) */ 2374 o1 = 0xf5d0f000 2375 2376 o1 |= (uint32(p.From.Reg) & 15) << 16 2377 if p.From.Offset < 0 { 2378 o1 &^= (1 << 23) 2379 o1 |= uint32((-p.From.Offset) & 0xfff) 2380 } else { 2381 o1 |= uint32(p.From.Offset & 0xfff) 2382 } 2383 2384 // This is supposed to be something that stops execution. 2385 // It's not supposed to be reached, ever, but if it is, we'd 2386 // like to be able to tell how we got there. Assemble as 2387 // 0xf7fabcfd which is guaranteed to raise undefined instruction 2388 // exception. 2389 case 96: /* UNDEF */ 2390 o1 = 0xf7fabcfd 2391 2392 case 97: /* CLZ Rm, Rd */ 2393 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2394 2395 o1 |= (uint32(p.To.Reg) & 15) << 12 2396 o1 |= (uint32(p.From.Reg) & 15) << 0 2397 2398 case 98: /* MULW{T,B} Rs, Rm, Rd */ 2399 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2400 2401 o1 |= (uint32(p.To.Reg) & 15) << 16 2402 o1 |= (uint32(p.From.Reg) & 15) << 8 2403 o1 |= (uint32(p.Reg) & 15) << 0 2404 2405 case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ 2406 o1 = oprrr(ctxt, int(p.As), int(p.Scond)) 2407 2408 o1 |= (uint32(p.To.Reg) & 15) << 12 2409 o1 |= (uint32(p.From.Reg) & 15) << 8 2410 o1 |= (uint32(p.Reg) & 15) << 0 2411 o1 |= uint32((p.To.Offset & 15) << 16) 2412 2413 // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle; 2414 // DATABUNDLEEND: zero width alignment marker 2415 case 100: 2416 if p.As == ADATABUNDLE { 2417 o1 = 0xe125be70 2418 } 2419 } 2420 2421 out[0] = o1 2422 out[1] = o2 2423 out[2] = o3 2424 out[3] = o4 2425 out[4] = o5 2426 out[5] = o6 2427 return 2428 } 2429 2430 func mov(ctxt *obj.Link, p *obj.Prog) uint32 { 2431 aclass(ctxt, &p.From) 2432 o1 := oprrr(ctxt, int(p.As), int(p.Scond)) 2433 o1 |= uint32(p.From.Offset) 2434 rt := int(p.To.Reg) 2435 if p.To.Type == obj.TYPE_NONE { 2436 rt = 0 2437 } 2438 r := int(p.Reg) 2439 if p.As == AMOVW || p.As == AMVN { 2440 r = 0 2441 } else if r == 0 { 2442 r = rt 2443 } 2444 o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12 2445 return o1 2446 } 2447 2448 func oprrr(ctxt *obj.Link, a int, sc int) uint32 { 2449 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2450 if sc&C_SBIT != 0 { 2451 o |= 1 << 20 2452 } 2453 if sc&(C_PBIT|C_WBIT) != 0 { 2454 ctxt.Diag(".nil/.W on dp instruction") 2455 } 2456 switch a { 2457 case AMULU, AMUL: 2458 return o | 0x0<<21 | 0x9<<4 2459 case AMULA: 2460 return o | 0x1<<21 | 0x9<<4 2461 case AMULLU: 2462 return o | 0x4<<21 | 0x9<<4 2463 case AMULL: 2464 return o | 0x6<<21 | 0x9<<4 2465 case AMULALU: 2466 return o | 0x5<<21 | 0x9<<4 2467 case AMULAL: 2468 return o | 0x7<<21 | 0x9<<4 2469 case AAND: 2470 return o | 0x0<<21 2471 case AEOR: 2472 return o | 0x1<<21 2473 case ASUB: 2474 return o | 0x2<<21 2475 case ARSB: 2476 return o | 0x3<<21 2477 case AADD: 2478 return o | 0x4<<21 2479 case AADC: 2480 return o | 0x5<<21 2481 case ASBC: 2482 return o | 0x6<<21 2483 case ARSC: 2484 return o | 0x7<<21 2485 case ATST: 2486 return o | 0x8<<21 | 1<<20 2487 case ATEQ: 2488 return o | 0x9<<21 | 1<<20 2489 case ACMP: 2490 return o | 0xa<<21 | 1<<20 2491 case ACMN: 2492 return o | 0xb<<21 | 1<<20 2493 case AORR: 2494 return o | 0xc<<21 2495 2496 case AMOVB, AMOVH, AMOVW: 2497 return o | 0xd<<21 2498 case ABIC: 2499 return o | 0xe<<21 2500 case AMVN: 2501 return o | 0xf<<21 2502 case ASLL: 2503 return o | 0xd<<21 | 0<<5 2504 case ASRL: 2505 return o | 0xd<<21 | 1<<5 2506 case ASRA: 2507 return o | 0xd<<21 | 2<<5 2508 case ASWI: 2509 return o | 0xf<<24 2510 2511 case AADDD: 2512 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4 2513 case AADDF: 2514 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4 2515 case ASUBD: 2516 return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4 2517 case ASUBF: 2518 return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4 2519 case AMULD: 2520 return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4 2521 case AMULF: 2522 return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4 2523 case ADIVD: 2524 return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4 2525 case ADIVF: 2526 return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4 2527 case ASQRTD: 2528 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4 2529 case ASQRTF: 2530 return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4 2531 case AABSD: 2532 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4 2533 case AABSF: 2534 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4 2535 case ACMPD: 2536 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4 2537 case ACMPF: 2538 return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4 2539 2540 case AMOVF: 2541 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4 2542 case AMOVD: 2543 return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4 2544 2545 case AMOVDF: 2546 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof 2547 case AMOVFD: 2548 return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof 2549 2550 case AMOVWF: 2551 if sc&C_UBIT == 0 { 2552 o |= 1 << 7 /* signed */ 2553 } 2554 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double 2555 2556 case AMOVWD: 2557 if sc&C_UBIT == 0 { 2558 o |= 1 << 7 /* signed */ 2559 } 2560 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double 2561 2562 case AMOVFW: 2563 if sc&C_UBIT == 0 { 2564 o |= 1 << 16 /* signed */ 2565 } 2566 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc 2567 2568 case AMOVDW: 2569 if sc&C_UBIT == 0 { 2570 o |= 1 << 16 /* signed */ 2571 } 2572 return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc 2573 2574 case AMOVWF + ALAST: // copy WtoF 2575 return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4 2576 2577 case AMOVFW + ALAST: // copy FtoW 2578 return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4 2579 2580 case ACMP + ALAST: // cmp imm 2581 return o | 0x3<<24 | 0x5<<20 2582 2583 // CLZ doesn't support .nil 2584 case ACLZ: 2585 return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4 2586 2587 case AMULWT: 2588 return o&(0xf<<28) | 0x12<<20 | 0xe<<4 2589 2590 case AMULWB: 2591 return o&(0xf<<28) | 0x12<<20 | 0xa<<4 2592 2593 case AMULAWT: 2594 return o&(0xf<<28) | 0x12<<20 | 0xc<<4 2595 2596 case AMULAWB: 2597 return o&(0xf<<28) | 0x12<<20 | 0x8<<4 2598 2599 case ABL: // BLX REG 2600 return o&(0xf<<28) | 0x12fff3<<4 2601 } 2602 2603 ctxt.Diag("bad rrr %d", a) 2604 prasm(ctxt.Curp) 2605 return 0 2606 } 2607 2608 func opbra(ctxt *obj.Link, a int, sc int) uint32 { 2609 if sc&(C_SBIT|C_PBIT|C_WBIT) != 0 { 2610 ctxt.Diag(".nil/.nil/.W on bra instruction") 2611 } 2612 sc &= C_SCOND 2613 sc ^= C_SCOND_XOR 2614 if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY { 2615 return uint32(sc)<<28 | 0x5<<25 | 0x1<<24 2616 } 2617 if sc != 0xe { 2618 ctxt.Diag(".COND on bcond instruction") 2619 } 2620 switch a { 2621 case ABEQ: 2622 return 0x0<<28 | 0x5<<25 2623 case ABNE: 2624 return 0x1<<28 | 0x5<<25 2625 case ABCS: 2626 return 0x2<<28 | 0x5<<25 2627 case ABHS: 2628 return 0x2<<28 | 0x5<<25 2629 case ABCC: 2630 return 0x3<<28 | 0x5<<25 2631 case ABLO: 2632 return 0x3<<28 | 0x5<<25 2633 case ABMI: 2634 return 0x4<<28 | 0x5<<25 2635 case ABPL: 2636 return 0x5<<28 | 0x5<<25 2637 case ABVS: 2638 return 0x6<<28 | 0x5<<25 2639 case ABVC: 2640 return 0x7<<28 | 0x5<<25 2641 case ABHI: 2642 return 0x8<<28 | 0x5<<25 2643 case ABLS: 2644 return 0x9<<28 | 0x5<<25 2645 case ABGE: 2646 return 0xa<<28 | 0x5<<25 2647 case ABLT: 2648 return 0xb<<28 | 0x5<<25 2649 case ABGT: 2650 return 0xc<<28 | 0x5<<25 2651 case ABLE: 2652 return 0xd<<28 | 0x5<<25 2653 case AB: 2654 return 0xe<<28 | 0x5<<25 2655 } 2656 2657 ctxt.Diag("bad bra %v", obj.Aconv(a)) 2658 prasm(ctxt.Curp) 2659 return 0 2660 } 2661 2662 func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 { 2663 if sc&C_SBIT != 0 { 2664 ctxt.Diag(".nil on LDR/STR instruction") 2665 } 2666 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2667 if sc&C_PBIT == 0 { 2668 o |= 1 << 24 2669 } 2670 if sc&C_UBIT == 0 { 2671 o |= 1 << 23 2672 } 2673 if sc&C_WBIT != 0 { 2674 o |= 1 << 21 2675 } 2676 o |= 1<<26 | 1<<20 2677 if v < 0 { 2678 if sc&C_UBIT != 0 { 2679 ctxt.Diag(".U on neg offset") 2680 } 2681 v = -v 2682 o ^= 1 << 23 2683 } 2684 2685 if v >= 1<<12 || v < 0 { 2686 ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp) 2687 } 2688 o |= uint32(v) 2689 o |= (uint32(b) & 15) << 16 2690 o |= (uint32(r) & 15) << 12 2691 return o 2692 } 2693 2694 func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 { 2695 if sc&C_SBIT != 0 { 2696 ctxt.Diag(".nil on LDRH/STRH instruction") 2697 } 2698 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2699 if sc&C_PBIT == 0 { 2700 o |= 1 << 24 2701 } 2702 if sc&C_WBIT != 0 { 2703 o |= 1 << 21 2704 } 2705 o |= 1<<23 | 1<<20 | 0xb<<4 2706 if v < 0 { 2707 v = -v 2708 o ^= 1 << 23 2709 } 2710 2711 if v >= 1<<8 || v < 0 { 2712 ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp) 2713 } 2714 o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22 2715 o |= (uint32(b) & 15) << 16 2716 o |= (uint32(r) & 15) << 12 2717 return o 2718 } 2719 2720 func osr(ctxt *obj.Link, a int, r int, v int32, b int, sc int) uint32 { 2721 o := olr(ctxt, v, b, r, sc) ^ (1 << 20) 2722 if a != AMOVW { 2723 o |= 1 << 22 2724 } 2725 return o 2726 } 2727 2728 func oshr(ctxt *obj.Link, r int, v int32, b int, sc int) uint32 { 2729 o := olhr(ctxt, v, b, r, sc) ^ (1 << 20) 2730 return o 2731 } 2732 2733 func osrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 { 2734 return olr(ctxt, int32(i), b, r, sc) ^ (1<<25 | 1<<20) 2735 } 2736 2737 func oshrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 { 2738 return olhr(ctxt, int32(i), b, r, sc) ^ (1<<22 | 1<<20) 2739 } 2740 2741 func olrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 { 2742 return olr(ctxt, int32(i), b, r, sc) ^ (1 << 25) 2743 } 2744 2745 func olhrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 { 2746 return olhr(ctxt, int32(i), b, r, sc) ^ (1 << 22) 2747 } 2748 2749 func ofsr(ctxt *obj.Link, a int, r int, v int32, b int, sc int, p *obj.Prog) uint32 { 2750 if sc&C_SBIT != 0 { 2751 ctxt.Diag(".nil on FLDR/FSTR instruction") 2752 } 2753 o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28 2754 if sc&C_PBIT == 0 { 2755 o |= 1 << 24 2756 } 2757 if sc&C_WBIT != 0 { 2758 o |= 1 << 21 2759 } 2760 o |= 6<<25 | 1<<24 | 1<<23 | 10<<8 2761 if v < 0 { 2762 v = -v 2763 o ^= 1 << 23 2764 } 2765 2766 if v&3 != 0 { 2767 ctxt.Diag("odd offset for floating point op: %d\n%v", v, p) 2768 } else if v >= 1<<10 || v < 0 { 2769 ctxt.Diag("literal span too large: %d\n%v", v, p) 2770 } 2771 o |= (uint32(v) >> 2) & 0xFF 2772 o |= (uint32(b) & 15) << 16 2773 o |= (uint32(r) & 15) << 12 2774 2775 switch a { 2776 default: 2777 ctxt.Diag("bad fst %v", obj.Aconv(a)) 2778 fallthrough 2779 2780 case AMOVD: 2781 o |= 1 << 8 2782 fallthrough 2783 2784 case AMOVF: 2785 break 2786 } 2787 2788 return o 2789 } 2790 2791 func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 { 2792 var o1 uint32 2793 if p.Pcond == nil { 2794 aclass(ctxt, a) 2795 v := immrot(^uint32(ctxt.Instoffset)) 2796 if v == 0 { 2797 ctxt.Diag("missing literal") 2798 prasm(p) 2799 return 0 2800 } 2801 2802 o1 = oprrr(ctxt, AMVN, int(p.Scond)&C_SCOND) 2803 o1 |= uint32(v) 2804 o1 |= (uint32(dr) & 15) << 12 2805 } else { 2806 v := int32(p.Pcond.Pc - p.Pc - 8) 2807 o1 = olr(ctxt, v, REGPC, dr, int(p.Scond)&C_SCOND) 2808 } 2809 2810 return o1 2811 } 2812 2813 func chipzero5(ctxt *obj.Link, e float64) int { 2814 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 2815 if ctxt.Goarm < 7 || e != 0 { 2816 return -1 2817 } 2818 return 0 2819 } 2820 2821 func chipfloat5(ctxt *obj.Link, e float64) int { 2822 // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. 2823 if ctxt.Goarm < 7 { 2824 return -1 2825 } 2826 2827 ei := math.Float64bits(e) 2828 l := uint32(ei) 2829 h := uint32(ei >> 32) 2830 2831 if l != 0 || h&0xffff != 0 { 2832 return -1 2833 } 2834 h1 := h & 0x7fc00000 2835 if h1 != 0x40000000 && h1 != 0x3fc00000 { 2836 return -1 2837 } 2838 n := 0 2839 2840 // sign bit (a) 2841 if h&0x80000000 != 0 { 2842 n |= 1 << 7 2843 } 2844 2845 // exp sign bit (b) 2846 if h1 == 0x3fc00000 { 2847 n |= 1 << 6 2848 } 2849 2850 // rest of exp and mantissa (cd-efgh) 2851 n |= int((h >> 16) & 0x3f) 2852 2853 //print("match %.8lux %.8lux %d\n", l, h, n); 2854 return n 2855 }