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