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