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