github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/obj/mips/asm0.go (about) 1 // cmd/9l/optab.c, cmd/9l/asmout.c from Vita Nuova. 2 // 3 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 4 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 5 // Portions Copyright © 1997-1999 Vita Nuova Limited 6 // Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) 7 // Portions Copyright © 2004,2006 Bruce Ellis 8 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 9 // Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others 10 // Portions Copyright © 2009 The Go Authors. All rights reserved. 11 // 12 // Permission is hereby granted, free of charge, to any person obtaining a copy 13 // of this software and associated documentation files (the "Software"), to deal 14 // in the Software without restriction, including without limitation the rights 15 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 // copies of the Software, and to permit persons to whom the Software is 17 // furnished to do so, subject to the following conditions: 18 // 19 // The above copyright notice and this permission notice shall be included in 20 // all copies or substantial portions of the Software. 21 // 22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 // THE SOFTWARE. 29 30 package mips 31 32 import ( 33 "fmt" 34 "log" 35 "sort" 36 37 "github.com/go-asm/go/cmd/obj" 38 "github.com/go-asm/go/cmd/objabi" 39 "github.com/go-asm/go/cmd/sys" 40 ) 41 42 // ctxt0 holds state while assembling a single function. 43 // Each function gets a fresh ctxt0. 44 // This allows for multiple functions to be safely concurrently assembled. 45 type ctxt0 struct { 46 ctxt *obj.Link 47 newprog obj.ProgAlloc 48 cursym *obj.LSym 49 autosize int32 50 instoffset int64 51 pc int64 52 } 53 54 // Instruction layout. 55 56 const ( 57 mips64FuncAlign = 8 58 ) 59 60 const ( 61 r0iszero = 1 62 ) 63 64 type Optab struct { 65 as obj.As 66 a1 uint8 67 a2 uint8 68 a3 uint8 69 type_ int8 70 size int8 71 param int16 72 family sys.ArchFamily // 0 means both sys.MIPS and sys.MIPS64 73 flag uint8 74 } 75 76 const ( 77 // Optab.flag 78 NOTUSETMP = 1 << iota // p expands to multiple instructions, but does NOT use REGTMP 79 ) 80 81 var optab = []Optab{ 82 {obj.ATEXT, C_LEXT, C_NONE, C_TEXTSIZE, 0, 0, 0, sys.MIPS64, 0}, 83 {obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0}, 84 85 {AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, 86 {AMOVV, C_REG, C_NONE, C_REG, 1, 4, 0, sys.MIPS64, 0}, 87 {AMOVB, C_REG, C_NONE, C_REG, 12, 8, 0, 0, NOTUSETMP}, 88 {AMOVBU, C_REG, C_NONE, C_REG, 13, 4, 0, 0, 0}, 89 {AMOVWU, C_REG, C_NONE, C_REG, 14, 8, 0, sys.MIPS64, NOTUSETMP}, 90 91 {ASUB, C_REG, C_REG, C_REG, 2, 4, 0, 0, 0}, 92 {ASUBV, C_REG, C_REG, C_REG, 2, 4, 0, sys.MIPS64, 0}, 93 {AADD, C_REG, C_REG, C_REG, 2, 4, 0, 0, 0}, 94 {AADDV, C_REG, C_REG, C_REG, 2, 4, 0, sys.MIPS64, 0}, 95 {AAND, C_REG, C_REG, C_REG, 2, 4, 0, 0, 0}, 96 {ASUB, C_REG, C_NONE, C_REG, 2, 4, 0, 0, 0}, 97 {ASUBV, C_REG, C_NONE, C_REG, 2, 4, 0, sys.MIPS64, 0}, 98 {AADD, C_REG, C_NONE, C_REG, 2, 4, 0, 0, 0}, 99 {AADDV, C_REG, C_NONE, C_REG, 2, 4, 0, sys.MIPS64, 0}, 100 {AAND, C_REG, C_NONE, C_REG, 2, 4, 0, 0, 0}, 101 {ACMOVN, C_REG, C_REG, C_REG, 2, 4, 0, 0, 0}, 102 {ANEGW, C_REG, C_NONE, C_REG, 2, 4, 0, 0, 0}, 103 {ANEGV, C_REG, C_NONE, C_REG, 2, 4, 0, sys.MIPS64, 0}, 104 105 {ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0}, 106 {ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0}, 107 {ASLLV, C_REG, C_NONE, C_REG, 9, 4, 0, sys.MIPS64, 0}, 108 {ASLLV, C_REG, C_REG, C_REG, 9, 4, 0, sys.MIPS64, 0}, 109 {ACLO, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0}, 110 111 {AADDF, C_FREG, C_NONE, C_FREG, 32, 4, 0, 0, 0}, 112 {AADDF, C_FREG, C_REG, C_FREG, 32, 4, 0, 0, 0}, 113 {ACMPEQF, C_FREG, C_REG, C_NONE, 32, 4, 0, 0, 0}, 114 {AABSF, C_FREG, C_NONE, C_FREG, 33, 4, 0, 0, 0}, 115 {AMOVVF, C_FREG, C_NONE, C_FREG, 33, 4, 0, sys.MIPS64, 0}, 116 {AMOVF, C_FREG, C_NONE, C_FREG, 33, 4, 0, 0, 0}, 117 {AMOVD, C_FREG, C_NONE, C_FREG, 33, 4, 0, 0, 0}, 118 119 {AMOVW, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64, 0}, 120 {AMOVWU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64, 0}, 121 {AMOVV, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64, 0}, 122 {AMOVB, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64, 0}, 123 {AMOVBU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64, 0}, 124 {AMOVWL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64, 0}, 125 {AMOVVL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64, 0}, 126 {AMOVW, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, 0, 0}, 127 {AMOVWU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, sys.MIPS64, 0}, 128 {AMOVV, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, sys.MIPS64, 0}, 129 {AMOVB, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, 0, 0}, 130 {AMOVBU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, 0, 0}, 131 {AMOVWL, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, 0, 0}, 132 {AMOVVL, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, sys.MIPS64, 0}, 133 {AMOVW, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, 0, 0}, 134 {AMOVWU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, sys.MIPS64, 0}, 135 {AMOVV, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, sys.MIPS64, 0}, 136 {AMOVB, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, 0, 0}, 137 {AMOVBU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, 0, 0}, 138 {AMOVWL, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, 0, 0}, 139 {AMOVVL, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, sys.MIPS64, 0}, 140 {ASC, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, 0, 0}, 141 {ASCV, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, sys.MIPS64, 0}, 142 143 {AMOVW, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64, 0}, 144 {AMOVWU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64, 0}, 145 {AMOVV, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64, 0}, 146 {AMOVB, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64, 0}, 147 {AMOVBU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64, 0}, 148 {AMOVWL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64, 0}, 149 {AMOVVL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB, sys.MIPS64, 0}, 150 {AMOVW, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, 0, 0}, 151 {AMOVWU, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, sys.MIPS64, 0}, 152 {AMOVV, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, sys.MIPS64, 0}, 153 {AMOVB, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, 0, 0}, 154 {AMOVBU, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, 0, 0}, 155 {AMOVWL, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, 0, 0}, 156 {AMOVVL, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP, sys.MIPS64, 0}, 157 {AMOVW, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, 0, 0}, 158 {AMOVWU, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, sys.MIPS64, 0}, 159 {AMOVV, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, sys.MIPS64, 0}, 160 {AMOVB, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, 0, 0}, 161 {AMOVBU, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, 0, 0}, 162 {AMOVWL, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, 0, 0}, 163 {AMOVVL, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, sys.MIPS64, 0}, 164 {ALL, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, 0, 0}, 165 {ALLV, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, sys.MIPS64, 0}, 166 167 {AMOVW, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, sys.MIPS64, 0}, 168 {AMOVWU, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, sys.MIPS64, 0}, 169 {AMOVV, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, sys.MIPS64, 0}, 170 {AMOVB, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, sys.MIPS64, 0}, 171 {AMOVBU, C_REG, C_NONE, C_LEXT, 35, 12, REGSB, sys.MIPS64, 0}, 172 {AMOVW, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, 0, 0}, 173 {AMOVWU, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, sys.MIPS64, 0}, 174 {AMOVV, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, sys.MIPS64, 0}, 175 {AMOVB, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, 0, 0}, 176 {AMOVBU, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP, 0, 0}, 177 {AMOVW, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, 0, 0}, 178 {AMOVWU, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, sys.MIPS64, 0}, 179 {AMOVV, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, sys.MIPS64, 0}, 180 {AMOVB, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, 0, 0}, 181 {AMOVBU, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, 0, 0}, 182 {ASC, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO, 0, 0}, 183 {AMOVW, C_REG, C_NONE, C_ADDR, 50, 8, 0, sys.MIPS, 0}, 184 {AMOVW, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64, 0}, 185 {AMOVWU, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64, 0}, 186 {AMOVV, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64, 0}, 187 {AMOVB, C_REG, C_NONE, C_ADDR, 50, 8, 0, sys.MIPS, 0}, 188 {AMOVB, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64, 0}, 189 {AMOVBU, C_REG, C_NONE, C_ADDR, 50, 8, 0, sys.MIPS, 0}, 190 {AMOVBU, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64, 0}, 191 {AMOVW, C_REG, C_NONE, C_TLS, 53, 8, 0, 0, NOTUSETMP}, 192 {AMOVWU, C_REG, C_NONE, C_TLS, 53, 8, 0, sys.MIPS64, NOTUSETMP}, 193 {AMOVV, C_REG, C_NONE, C_TLS, 53, 8, 0, sys.MIPS64, NOTUSETMP}, 194 {AMOVB, C_REG, C_NONE, C_TLS, 53, 8, 0, 0, NOTUSETMP}, 195 {AMOVBU, C_REG, C_NONE, C_TLS, 53, 8, 0, 0, NOTUSETMP}, 196 197 {AMOVW, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64, 0}, 198 {AMOVWU, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64, 0}, 199 {AMOVV, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64, 0}, 200 {AMOVB, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64, 0}, 201 {AMOVBU, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64, 0}, 202 {AMOVW, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, 0, 0}, 203 {AMOVWU, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, sys.MIPS64, 0}, 204 {AMOVV, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, sys.MIPS64, 0}, 205 {AMOVB, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, 0, 0}, 206 {AMOVBU, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP, 0, 0}, 207 {AMOVW, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, 0, 0}, 208 {AMOVWU, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, sys.MIPS64, 0}, 209 {AMOVV, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, sys.MIPS64, 0}, 210 {AMOVB, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, 0, 0}, 211 {AMOVBU, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO, 0, 0}, 212 {AMOVW, C_ADDR, C_NONE, C_REG, 51, 8, 0, sys.MIPS, 0}, 213 {AMOVW, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64, 0}, 214 {AMOVWU, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64, 0}, 215 {AMOVV, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64, 0}, 216 {AMOVB, C_ADDR, C_NONE, C_REG, 51, 8, 0, sys.MIPS, 0}, 217 {AMOVB, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64, 0}, 218 {AMOVBU, C_ADDR, C_NONE, C_REG, 51, 8, 0, sys.MIPS, 0}, 219 {AMOVBU, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64, 0}, 220 {AMOVW, C_TLS, C_NONE, C_REG, 54, 8, 0, 0, NOTUSETMP}, 221 {AMOVWU, C_TLS, C_NONE, C_REG, 54, 8, 0, sys.MIPS64, NOTUSETMP}, 222 {AMOVV, C_TLS, C_NONE, C_REG, 54, 8, 0, sys.MIPS64, NOTUSETMP}, 223 {AMOVB, C_TLS, C_NONE, C_REG, 54, 8, 0, 0, NOTUSETMP}, 224 {AMOVBU, C_TLS, C_NONE, C_REG, 54, 8, 0, 0, NOTUSETMP}, 225 226 {AMOVW, C_SECON, C_NONE, C_REG, 3, 4, REGSB, sys.MIPS64, 0}, 227 {AMOVV, C_SECON, C_NONE, C_REG, 3, 4, REGSB, sys.MIPS64, 0}, 228 {AMOVW, C_SACON, C_NONE, C_REG, 3, 4, REGSP, 0, 0}, 229 {AMOVV, C_SACON, C_NONE, C_REG, 3, 4, REGSP, sys.MIPS64, 0}, 230 {AMOVW, C_LECON, C_NONE, C_REG, 52, 8, REGSB, sys.MIPS, NOTUSETMP}, 231 {AMOVW, C_LECON, C_NONE, C_REG, 52, 12, REGSB, sys.MIPS64, NOTUSETMP}, 232 {AMOVV, C_LECON, C_NONE, C_REG, 52, 12, REGSB, sys.MIPS64, NOTUSETMP}, 233 234 {AMOVW, C_LACON, C_NONE, C_REG, 26, 12, REGSP, 0, 0}, 235 {AMOVV, C_LACON, C_NONE, C_REG, 26, 12, REGSP, sys.MIPS64, 0}, 236 {AMOVW, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO, 0, 0}, 237 {AMOVV, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO, sys.MIPS64, 0}, 238 {AMOVW, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO, 0, 0}, 239 {AMOVV, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO, sys.MIPS64, 0}, 240 {AMOVW, C_STCON, C_NONE, C_REG, 55, 8, 0, 0, NOTUSETMP}, 241 {AMOVV, C_STCON, C_NONE, C_REG, 55, 8, 0, sys.MIPS64, NOTUSETMP}, 242 243 {AMOVW, C_UCON, C_NONE, C_REG, 24, 4, 0, 0, 0}, 244 {AMOVV, C_UCON, C_NONE, C_REG, 24, 4, 0, sys.MIPS64, 0}, 245 {AMOVW, C_LCON, C_NONE, C_REG, 19, 8, 0, 0, NOTUSETMP}, 246 {AMOVV, C_LCON, C_NONE, C_REG, 19, 8, 0, sys.MIPS64, NOTUSETMP}, 247 248 {AMOVW, C_HI, C_NONE, C_REG, 20, 4, 0, 0, 0}, 249 {AMOVV, C_HI, C_NONE, C_REG, 20, 4, 0, sys.MIPS64, 0}, 250 {AMOVW, C_LO, C_NONE, C_REG, 20, 4, 0, 0, 0}, 251 {AMOVV, C_LO, C_NONE, C_REG, 20, 4, 0, sys.MIPS64, 0}, 252 {AMOVW, C_REG, C_NONE, C_HI, 21, 4, 0, 0, 0}, 253 {AMOVV, C_REG, C_NONE, C_HI, 21, 4, 0, sys.MIPS64, 0}, 254 {AMOVW, C_REG, C_NONE, C_LO, 21, 4, 0, 0, 0}, 255 {AMOVV, C_REG, C_NONE, C_LO, 21, 4, 0, sys.MIPS64, 0}, 256 257 {AMUL, C_REG, C_REG, C_NONE, 22, 4, 0, 0, 0}, 258 {AMUL, C_REG, C_REG, C_REG, 22, 4, 0, 0, 0}, 259 {AMULV, C_REG, C_REG, C_NONE, 22, 4, 0, sys.MIPS64, 0}, 260 261 {AADD, C_ADD0CON, C_REG, C_REG, 4, 4, 0, 0, 0}, 262 {AADD, C_ADD0CON, C_NONE, C_REG, 4, 4, 0, 0, 0}, 263 {AADD, C_ANDCON, C_REG, C_REG, 10, 8, 0, 0, 0}, 264 {AADD, C_ANDCON, C_NONE, C_REG, 10, 8, 0, 0, 0}, 265 266 {AADDV, C_ADD0CON, C_REG, C_REG, 4, 4, 0, sys.MIPS64, 0}, 267 {AADDV, C_ADD0CON, C_NONE, C_REG, 4, 4, 0, sys.MIPS64, 0}, 268 {AADDV, C_ANDCON, C_REG, C_REG, 10, 8, 0, sys.MIPS64, 0}, 269 {AADDV, C_ANDCON, C_NONE, C_REG, 10, 8, 0, sys.MIPS64, 0}, 270 271 {AAND, C_AND0CON, C_REG, C_REG, 4, 4, 0, 0, 0}, 272 {AAND, C_AND0CON, C_NONE, C_REG, 4, 4, 0, 0, 0}, 273 {AAND, C_ADDCON, C_REG, C_REG, 10, 8, 0, 0, 0}, 274 {AAND, C_ADDCON, C_NONE, C_REG, 10, 8, 0, 0, 0}, 275 276 {AADD, C_UCON, C_REG, C_REG, 25, 8, 0, 0, 0}, 277 {AADD, C_UCON, C_NONE, C_REG, 25, 8, 0, 0, 0}, 278 {AADDV, C_UCON, C_REG, C_REG, 25, 8, 0, sys.MIPS64, 0}, 279 {AADDV, C_UCON, C_NONE, C_REG, 25, 8, 0, sys.MIPS64, 0}, 280 {AAND, C_UCON, C_REG, C_REG, 25, 8, 0, 0, 0}, 281 {AAND, C_UCON, C_NONE, C_REG, 25, 8, 0, 0, 0}, 282 283 {AADD, C_LCON, C_NONE, C_REG, 23, 12, 0, 0, 0}, 284 {AADDV, C_LCON, C_NONE, C_REG, 23, 12, 0, sys.MIPS64, 0}, 285 {AAND, C_LCON, C_NONE, C_REG, 23, 12, 0, 0, 0}, 286 {AADD, C_LCON, C_REG, C_REG, 23, 12, 0, 0, 0}, 287 {AADDV, C_LCON, C_REG, C_REG, 23, 12, 0, sys.MIPS64, 0}, 288 {AAND, C_LCON, C_REG, C_REG, 23, 12, 0, 0, 0}, 289 290 {ASLL, C_SCON, C_REG, C_REG, 16, 4, 0, 0, 0}, 291 {ASLL, C_SCON, C_NONE, C_REG, 16, 4, 0, 0, 0}, 292 293 {ASLLV, C_SCON, C_REG, C_REG, 16, 4, 0, sys.MIPS64, 0}, 294 {ASLLV, C_SCON, C_NONE, C_REG, 16, 4, 0, sys.MIPS64, 0}, 295 296 {ASYSCALL, C_NONE, C_NONE, C_NONE, 5, 4, 0, 0, 0}, 297 298 {ABEQ, C_REG, C_REG, C_SBRA, 6, 4, 0, 0, 0}, 299 {ABEQ, C_REG, C_NONE, C_SBRA, 6, 4, 0, 0, 0}, 300 {ABLEZ, C_REG, C_NONE, C_SBRA, 6, 4, 0, 0, 0}, 301 {ABFPT, C_NONE, C_NONE, C_SBRA, 6, 8, 0, 0, NOTUSETMP}, 302 303 {AJMP, C_NONE, C_NONE, C_LBRA, 11, 4, 0, 0, 0}, 304 {AJAL, C_NONE, C_NONE, C_LBRA, 11, 4, 0, 0, 0}, 305 306 {AJMP, C_NONE, C_NONE, C_ZOREG, 18, 4, REGZERO, 0, 0}, 307 {AJAL, C_NONE, C_NONE, C_ZOREG, 18, 4, REGLINK, 0, 0}, 308 309 {AMOVW, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB, sys.MIPS64, 0}, 310 {AMOVF, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB, sys.MIPS64, 0}, 311 {AMOVD, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB, sys.MIPS64, 0}, 312 {AMOVW, C_SAUTO, C_NONE, C_FREG, 27, 4, REGSP, sys.MIPS64, 0}, 313 {AMOVF, C_SAUTO, C_NONE, C_FREG, 27, 4, REGSP, 0, 0}, 314 {AMOVD, C_SAUTO, C_NONE, C_FREG, 27, 4, REGSP, 0, 0}, 315 {AMOVW, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO, sys.MIPS64, 0}, 316 {AMOVF, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO, 0, 0}, 317 {AMOVD, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO, 0, 0}, 318 319 {AMOVW, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB, sys.MIPS64, 0}, 320 {AMOVF, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB, sys.MIPS64, 0}, 321 {AMOVD, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB, sys.MIPS64, 0}, 322 {AMOVW, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP, sys.MIPS64, 0}, 323 {AMOVF, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP, 0, 0}, 324 {AMOVD, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP, 0, 0}, 325 {AMOVW, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO, sys.MIPS64, 0}, 326 {AMOVF, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO, 0, 0}, 327 {AMOVD, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO, 0, 0}, 328 {AMOVF, C_ADDR, C_NONE, C_FREG, 51, 8, 0, sys.MIPS, 0}, 329 {AMOVF, C_ADDR, C_NONE, C_FREG, 51, 12, 0, sys.MIPS64, 0}, 330 {AMOVD, C_ADDR, C_NONE, C_FREG, 51, 8, 0, sys.MIPS, 0}, 331 {AMOVD, C_ADDR, C_NONE, C_FREG, 51, 12, 0, sys.MIPS64, 0}, 332 333 {AMOVW, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB, sys.MIPS64, 0}, 334 {AMOVF, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB, sys.MIPS64, 0}, 335 {AMOVD, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB, sys.MIPS64, 0}, 336 {AMOVW, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP, sys.MIPS64, 0}, 337 {AMOVF, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP, 0, 0}, 338 {AMOVD, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP, 0, 0}, 339 {AMOVW, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO, sys.MIPS64, 0}, 340 {AMOVF, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO, 0, 0}, 341 {AMOVD, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO, 0, 0}, 342 343 {AMOVW, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB, sys.MIPS64, 0}, 344 {AMOVF, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB, sys.MIPS64, 0}, 345 {AMOVD, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB, sys.MIPS64, 0}, 346 {AMOVW, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP, sys.MIPS64, 0}, 347 {AMOVF, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP, 0, 0}, 348 {AMOVD, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP, 0, 0}, 349 {AMOVW, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO, sys.MIPS64, 0}, 350 {AMOVF, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO, 0, 0}, 351 {AMOVD, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO, 0, 0}, 352 {AMOVF, C_FREG, C_NONE, C_ADDR, 50, 8, 0, sys.MIPS, 0}, 353 {AMOVF, C_FREG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64, 0}, 354 {AMOVD, C_FREG, C_NONE, C_ADDR, 50, 8, 0, sys.MIPS, 0}, 355 {AMOVD, C_FREG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64, 0}, 356 357 {AMOVW, C_REG, C_NONE, C_FREG, 30, 4, 0, 0, 0}, 358 {AMOVW, C_FREG, C_NONE, C_REG, 31, 4, 0, 0, 0}, 359 {AMOVV, C_REG, C_NONE, C_FREG, 47, 4, 0, sys.MIPS64, 0}, 360 {AMOVV, C_FREG, C_NONE, C_REG, 48, 4, 0, sys.MIPS64, 0}, 361 362 {AMOVW, C_ADDCON, C_NONE, C_FREG, 34, 8, 0, sys.MIPS64, 0}, 363 {AMOVW, C_ANDCON, C_NONE, C_FREG, 34, 8, 0, sys.MIPS64, 0}, 364 365 {AMOVW, C_REG, C_NONE, C_MREG, 37, 4, 0, 0, 0}, 366 {AMOVV, C_REG, C_NONE, C_MREG, 37, 4, 0, sys.MIPS64, 0}, 367 {AMOVW, C_MREG, C_NONE, C_REG, 38, 4, 0, 0, 0}, 368 {AMOVV, C_MREG, C_NONE, C_REG, 38, 4, 0, sys.MIPS64, 0}, 369 370 {AWORD, C_LCON, C_NONE, C_NONE, 40, 4, 0, 0, 0}, 371 372 {AMOVW, C_REG, C_NONE, C_FCREG, 41, 4, 0, 0, 0}, 373 {AMOVV, C_REG, C_NONE, C_FCREG, 41, 4, 0, sys.MIPS64, 0}, 374 {AMOVW, C_FCREG, C_NONE, C_REG, 42, 4, 0, 0, 0}, 375 {AMOVV, C_FCREG, C_NONE, C_REG, 42, 4, 0, sys.MIPS64, 0}, 376 377 {ATEQ, C_SCON, C_REG, C_REG, 15, 4, 0, 0, 0}, 378 {ATEQ, C_SCON, C_NONE, C_REG, 15, 4, 0, 0, 0}, 379 {ACMOVT, C_REG, C_NONE, C_REG, 17, 4, 0, 0, 0}, 380 381 {AVMOVB, C_SCON, C_NONE, C_WREG, 56, 4, 0, sys.MIPS64, 0}, 382 {AVMOVB, C_ADDCON, C_NONE, C_WREG, 56, 4, 0, sys.MIPS64, 0}, 383 {AVMOVB, C_SOREG, C_NONE, C_WREG, 57, 4, 0, sys.MIPS64, 0}, 384 {AVMOVB, C_WREG, C_NONE, C_SOREG, 58, 4, 0, sys.MIPS64, 0}, 385 386 {AWSBH, C_REG, C_NONE, C_REG, 59, 4, 0, 0, 0}, 387 {ADSBH, C_REG, C_NONE, C_REG, 59, 4, 0, sys.MIPS64, 0}, 388 389 {ABREAK, C_REG, C_NONE, C_SEXT, 7, 4, REGSB, sys.MIPS64, 0}, /* really CACHE instruction */ 390 {ABREAK, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP, sys.MIPS64, 0}, 391 {ABREAK, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO, sys.MIPS64, 0}, 392 {ABREAK, C_NONE, C_NONE, C_NONE, 5, 4, 0, 0, 0}, 393 394 {obj.AUNDEF, C_NONE, C_NONE, C_NONE, 49, 4, 0, 0, 0}, 395 {obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0}, 396 {obj.AFUNCDATA, C_SCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0}, 397 {obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, 398 {obj.ANOP, C_LCON, C_NONE, C_NONE, 0, 0, 0, 0, 0}, // nop variants, see #40689 399 {obj.ANOP, C_REG, C_NONE, C_NONE, 0, 0, 0, 0, 0}, 400 {obj.ANOP, C_FREG, C_NONE, C_NONE, 0, 0, 0, 0, 0}, 401 {obj.ADUFFZERO, C_NONE, C_NONE, C_LBRA, 11, 4, 0, 0, 0}, // same as AJMP 402 {obj.ADUFFCOPY, C_NONE, C_NONE, C_LBRA, 11, 4, 0, 0, 0}, // same as AJMP 403 404 {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0}, 405 } 406 407 var oprange [ALAST & obj.AMask][]Optab 408 409 var xcmp [C_NCLASS][C_NCLASS]bool 410 411 func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { 412 if ctxt.Retpoline { 413 ctxt.Diag("-spectre=ret not supported on mips") 414 ctxt.Retpoline = false // don't keep printing 415 } 416 417 p := cursym.Func().Text 418 if p == nil || p.Link == nil { // handle external functions and ELF section symbols 419 return 420 } 421 422 c := ctxt0{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: int32(p.To.Offset + ctxt.Arch.FixedFrameSize)} 423 424 if oprange[AOR&obj.AMask] == nil { 425 c.ctxt.Diag("mips ops not initialized, call mips.buildop first") 426 } 427 428 pc := int64(0) 429 p.Pc = pc 430 431 var m int 432 var o *Optab 433 for p = p.Link; p != nil; p = p.Link { 434 p.Pc = pc 435 o = c.oplook(p) 436 m = int(o.size) 437 if m == 0 { 438 if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA { 439 c.ctxt.Diag("zero-width instruction\n%v", p) 440 } 441 continue 442 } 443 444 pc += int64(m) 445 } 446 447 c.cursym.Size = pc 448 449 /* 450 * if any procedure is large enough to 451 * generate a large SBRA branch, then 452 * generate extra passes putting branches 453 * around jmps to fix. this is rare. 454 */ 455 bflag := 1 456 457 var otxt int64 458 var q *obj.Prog 459 for bflag != 0 { 460 bflag = 0 461 pc = 0 462 for p = c.cursym.Func().Text.Link; p != nil; p = p.Link { 463 p.Pc = pc 464 o = c.oplook(p) 465 466 // very large conditional branches 467 if o.type_ == 6 && p.To.Target() != nil { 468 otxt = p.To.Target().Pc - pc 469 if otxt < -(1<<17)+10 || otxt >= (1<<17)-10 { 470 q = c.newprog() 471 q.Link = p.Link 472 p.Link = q 473 q.As = AJMP 474 q.Pos = p.Pos 475 q.To.Type = obj.TYPE_BRANCH 476 q.To.SetTarget(p.To.Target()) 477 p.To.SetTarget(q) 478 q = c.newprog() 479 q.Link = p.Link 480 p.Link = q 481 q.As = AJMP 482 q.Pos = p.Pos 483 q.To.Type = obj.TYPE_BRANCH 484 q.To.SetTarget(q.Link.Link) 485 486 c.addnop(p.Link) 487 c.addnop(p) 488 bflag = 1 489 } 490 } 491 492 m = int(o.size) 493 if m == 0 { 494 if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA { 495 c.ctxt.Diag("zero-width instruction\n%v", p) 496 } 497 continue 498 } 499 500 pc += int64(m) 501 } 502 503 c.cursym.Size = pc 504 } 505 if c.ctxt.Arch.Family == sys.MIPS64 { 506 pc += -pc & (mips64FuncAlign - 1) 507 } 508 c.cursym.Size = pc 509 510 /* 511 * lay out the code, emitting code and data relocations. 512 */ 513 514 c.cursym.Grow(c.cursym.Size) 515 516 bp := c.cursym.P 517 var i int32 518 var out [4]uint32 519 for p := c.cursym.Func().Text.Link; p != nil; p = p.Link { 520 c.pc = p.Pc 521 o = c.oplook(p) 522 if int(o.size) > 4*len(out) { 523 log.Fatalf("out array in span0 is too small, need at least %d for %v", o.size/4, p) 524 } 525 c.asmout(p, o, out[:]) 526 for i = 0; i < int32(o.size/4); i++ { 527 c.ctxt.Arch.ByteOrder.PutUint32(bp, out[i]) 528 bp = bp[4:] 529 } 530 } 531 532 // Mark nonpreemptible instruction sequences. 533 // We use REGTMP as a scratch register during call injection, 534 // so instruction sequences that use REGTMP are unsafe to 535 // preempt asynchronously. 536 obj.MarkUnsafePoints(c.ctxt, c.cursym.Func().Text, c.newprog, c.isUnsafePoint, c.isRestartable) 537 } 538 539 // isUnsafePoint returns whether p is an unsafe point. 540 func (c *ctxt0) isUnsafePoint(p *obj.Prog) bool { 541 // If p explicitly uses REGTMP, it's unsafe to preempt, because the 542 // preemption sequence clobbers REGTMP. 543 return p.From.Reg == REGTMP || p.To.Reg == REGTMP || p.Reg == REGTMP 544 } 545 546 // isRestartable returns whether p is a multi-instruction sequence that, 547 // if preempted, can be restarted. 548 func (c *ctxt0) isRestartable(p *obj.Prog) bool { 549 if c.isUnsafePoint(p) { 550 return false 551 } 552 // If p is a multi-instruction sequence with uses REGTMP inserted by 553 // the assembler in order to materialize a large constant/offset, we 554 // can restart p (at the start of the instruction sequence), recompute 555 // the content of REGTMP, upon async preemption. Currently, all cases 556 // of assembler-inserted REGTMP fall into this category. 557 // If p doesn't use REGTMP, it can be simply preempted, so we don't 558 // mark it. 559 o := c.oplook(p) 560 return o.size > 4 && o.flag&NOTUSETMP == 0 561 } 562 563 func isint32(v int64) bool { 564 return int64(int32(v)) == v 565 } 566 567 func isuint32(v uint64) bool { 568 return uint64(uint32(v)) == v 569 } 570 571 func (c *ctxt0) aclass(a *obj.Addr) int { 572 switch a.Type { 573 case obj.TYPE_NONE: 574 return C_NONE 575 576 case obj.TYPE_REG: 577 if REG_R0 <= a.Reg && a.Reg <= REG_R31 { 578 return C_REG 579 } 580 if REG_F0 <= a.Reg && a.Reg <= REG_F31 { 581 return C_FREG 582 } 583 if REG_M0 <= a.Reg && a.Reg <= REG_M31 { 584 return C_MREG 585 } 586 if REG_FCR0 <= a.Reg && a.Reg <= REG_FCR31 { 587 return C_FCREG 588 } 589 if REG_W0 <= a.Reg && a.Reg <= REG_W31 { 590 return C_WREG 591 } 592 if a.Reg == REG_LO { 593 return C_LO 594 } 595 if a.Reg == REG_HI { 596 return C_HI 597 } 598 return C_GOK 599 600 case obj.TYPE_MEM: 601 switch a.Name { 602 case obj.NAME_EXTERN, 603 obj.NAME_STATIC: 604 if a.Sym == nil { 605 break 606 } 607 c.instoffset = a.Offset 608 if a.Sym != nil { // use relocation 609 if a.Sym.Type == objabi.STLSBSS { 610 return C_TLS 611 } 612 return C_ADDR 613 } 614 return C_LEXT 615 616 case obj.NAME_AUTO: 617 if a.Reg == REGSP { 618 // unset base register for better printing, since 619 // a.Offset is still relative to pseudo-SP. 620 a.Reg = obj.REG_NONE 621 } 622 c.instoffset = int64(c.autosize) + a.Offset 623 if c.instoffset >= -BIG && c.instoffset < BIG { 624 return C_SAUTO 625 } 626 return C_LAUTO 627 628 case obj.NAME_PARAM: 629 if a.Reg == REGSP { 630 // unset base register for better printing, since 631 // a.Offset is still relative to pseudo-FP. 632 a.Reg = obj.REG_NONE 633 } 634 c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.Arch.FixedFrameSize 635 if c.instoffset >= -BIG && c.instoffset < BIG { 636 return C_SAUTO 637 } 638 return C_LAUTO 639 640 case obj.NAME_NONE: 641 c.instoffset = a.Offset 642 if c.instoffset == 0 { 643 return C_ZOREG 644 } 645 if c.instoffset >= -BIG && c.instoffset < BIG { 646 return C_SOREG 647 } 648 return C_LOREG 649 } 650 651 return C_GOK 652 653 case obj.TYPE_TEXTSIZE: 654 return C_TEXTSIZE 655 656 case obj.TYPE_CONST, 657 obj.TYPE_ADDR: 658 switch a.Name { 659 case obj.NAME_NONE: 660 c.instoffset = a.Offset 661 if a.Reg != obj.REG_NONE { 662 if -BIG <= c.instoffset && c.instoffset <= BIG { 663 return C_SACON 664 } 665 if isint32(c.instoffset) { 666 return C_LACON 667 } 668 return C_DACON 669 } 670 671 case obj.NAME_EXTERN, 672 obj.NAME_STATIC: 673 s := a.Sym 674 if s == nil { 675 return C_GOK 676 } 677 678 c.instoffset = a.Offset 679 if s.Type == objabi.STLSBSS { 680 return C_STCON // address of TLS variable 681 } 682 return C_LECON 683 684 case obj.NAME_AUTO: 685 if a.Reg == REGSP { 686 // unset base register for better printing, since 687 // a.Offset is still relative to pseudo-SP. 688 a.Reg = obj.REG_NONE 689 } 690 c.instoffset = int64(c.autosize) + a.Offset 691 if c.instoffset >= -BIG && c.instoffset < BIG { 692 return C_SACON 693 } 694 return C_LACON 695 696 case obj.NAME_PARAM: 697 if a.Reg == REGSP { 698 // unset base register for better printing, since 699 // a.Offset is still relative to pseudo-FP. 700 a.Reg = obj.REG_NONE 701 } 702 c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.Arch.FixedFrameSize 703 if c.instoffset >= -BIG && c.instoffset < BIG { 704 return C_SACON 705 } 706 return C_LACON 707 708 default: 709 return C_GOK 710 } 711 712 if c.instoffset >= 0 { 713 if c.instoffset == 0 { 714 return C_ZCON 715 } 716 if c.instoffset <= 0x7fff { 717 return C_SCON 718 } 719 if c.instoffset <= 0xffff { 720 return C_ANDCON 721 } 722 if c.instoffset&0xffff == 0 && isuint32(uint64(c.instoffset)) { /* && ((instoffset & (1<<31)) == 0) */ 723 return C_UCON 724 } 725 if isint32(c.instoffset) || isuint32(uint64(c.instoffset)) { 726 return C_LCON 727 } 728 return C_LCON // C_DCON 729 } 730 731 if c.instoffset >= -0x8000 { 732 return C_ADDCON 733 } 734 if c.instoffset&0xffff == 0 && isint32(c.instoffset) { 735 return C_UCON 736 } 737 if isint32(c.instoffset) { 738 return C_LCON 739 } 740 return C_LCON // C_DCON 741 742 case obj.TYPE_BRANCH: 743 return C_SBRA 744 } 745 746 return C_GOK 747 } 748 749 func prasm(p *obj.Prog) { 750 fmt.Printf("%v\n", p) 751 } 752 753 func (c *ctxt0) oplook(p *obj.Prog) *Optab { 754 if oprange[AOR&obj.AMask] == nil { 755 c.ctxt.Diag("mips ops not initialized, call mips.buildop first") 756 } 757 758 a1 := int(p.Optab) 759 if a1 != 0 { 760 return &optab[a1-1] 761 } 762 a1 = int(p.From.Class) 763 if a1 == 0 { 764 a1 = c.aclass(&p.From) + 1 765 p.From.Class = int8(a1) 766 } 767 768 a1-- 769 a3 := int(p.To.Class) 770 if a3 == 0 { 771 a3 = c.aclass(&p.To) + 1 772 p.To.Class = int8(a3) 773 } 774 775 a3-- 776 a2 := C_NONE 777 if p.Reg != obj.REG_NONE { 778 a2 = C_REG 779 } 780 781 ops := oprange[p.As&obj.AMask] 782 c1 := &xcmp[a1] 783 c3 := &xcmp[a3] 784 for i := range ops { 785 op := &ops[i] 786 if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] && (op.family == 0 || c.ctxt.Arch.Family == op.family) { 787 p.Optab = uint16(cap(optab) - cap(ops) + i + 1) 788 return op 789 } 790 } 791 792 c.ctxt.Diag("illegal combination %v %v %v %v", p.As, DRconv(a1), DRconv(a2), DRconv(a3)) 793 prasm(p) 794 // Turn illegal instruction into an UNDEF, avoid crashing in asmout. 795 return &Optab{obj.AUNDEF, C_NONE, C_NONE, C_NONE, 49, 4, 0, 0, 0} 796 } 797 798 func cmp(a int, b int) bool { 799 if a == b { 800 return true 801 } 802 switch a { 803 case C_LCON: 804 if b == C_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON { 805 return true 806 } 807 808 case C_ADD0CON: 809 if b == C_ADDCON { 810 return true 811 } 812 fallthrough 813 814 case C_ADDCON: 815 if b == C_ZCON || b == C_SCON { 816 return true 817 } 818 819 case C_AND0CON: 820 if b == C_ANDCON { 821 return true 822 } 823 fallthrough 824 825 case C_ANDCON: 826 if b == C_ZCON || b == C_SCON { 827 return true 828 } 829 830 case C_UCON: 831 if b == C_ZCON { 832 return true 833 } 834 835 case C_SCON: 836 if b == C_ZCON { 837 return true 838 } 839 840 case C_LACON: 841 if b == C_SACON { 842 return true 843 } 844 845 case C_LBRA: 846 if b == C_SBRA { 847 return true 848 } 849 850 case C_LEXT: 851 if b == C_SEXT { 852 return true 853 } 854 855 case C_LAUTO: 856 if b == C_SAUTO { 857 return true 858 } 859 860 case C_REG: 861 if b == C_ZCON { 862 return r0iszero != 0 /*TypeKind(100016)*/ 863 } 864 865 case C_LOREG: 866 if b == C_ZOREG || b == C_SOREG { 867 return true 868 } 869 870 case C_SOREG: 871 if b == C_ZOREG { 872 return true 873 } 874 } 875 876 return false 877 } 878 879 type ocmp []Optab 880 881 func (x ocmp) Len() int { 882 return len(x) 883 } 884 885 func (x ocmp) Swap(i, j int) { 886 x[i], x[j] = x[j], x[i] 887 } 888 889 func (x ocmp) Less(i, j int) bool { 890 p1 := &x[i] 891 p2 := &x[j] 892 n := int(p1.as) - int(p2.as) 893 if n != 0 { 894 return n < 0 895 } 896 n = int(p1.a1) - int(p2.a1) 897 if n != 0 { 898 return n < 0 899 } 900 n = int(p1.a2) - int(p2.a2) 901 if n != 0 { 902 return n < 0 903 } 904 n = int(p1.a3) - int(p2.a3) 905 if n != 0 { 906 return n < 0 907 } 908 return false 909 } 910 911 func opset(a, b0 obj.As) { 912 oprange[a&obj.AMask] = oprange[b0] 913 } 914 915 func buildop(ctxt *obj.Link) { 916 if oprange[AOR&obj.AMask] != nil { 917 // Already initialized; stop now. 918 // This happens in the cmd/asm tests, 919 // each of which re-initializes the arch. 920 return 921 } 922 923 var n int 924 925 for i := 0; i < C_NCLASS; i++ { 926 for n = 0; n < C_NCLASS; n++ { 927 if cmp(n, i) { 928 xcmp[i][n] = true 929 } 930 } 931 } 932 for n = 0; optab[n].as != obj.AXXX; n++ { 933 } 934 sort.Sort(ocmp(optab[:n])) 935 for i := 0; i < n; i++ { 936 r := optab[i].as 937 r0 := r & obj.AMask 938 start := i 939 for optab[i].as == r { 940 i++ 941 } 942 oprange[r0] = optab[start:i] 943 i-- 944 945 switch r { 946 default: 947 ctxt.Diag("unknown op in build: %v", r) 948 ctxt.DiagFlush() 949 log.Fatalf("bad code") 950 951 case AABSF: 952 opset(AMOVFD, r0) 953 opset(AMOVDF, r0) 954 opset(AMOVWF, r0) 955 opset(AMOVFW, r0) 956 opset(AMOVWD, r0) 957 opset(AMOVDW, r0) 958 opset(ANEGF, r0) 959 opset(ANEGD, r0) 960 opset(AABSD, r0) 961 opset(ATRUNCDW, r0) 962 opset(ATRUNCFW, r0) 963 opset(ASQRTF, r0) 964 opset(ASQRTD, r0) 965 966 case AMOVVF: 967 opset(AMOVVD, r0) 968 opset(AMOVFV, r0) 969 opset(AMOVDV, r0) 970 opset(ATRUNCDV, r0) 971 opset(ATRUNCFV, r0) 972 973 case AADD: 974 opset(ASGT, r0) 975 opset(ASGTU, r0) 976 opset(AADDU, r0) 977 978 case AADDV: 979 opset(AADDVU, r0) 980 981 case AADDF: 982 opset(ADIVF, r0) 983 opset(ADIVD, r0) 984 opset(AMULF, r0) 985 opset(AMULD, r0) 986 opset(ASUBF, r0) 987 opset(ASUBD, r0) 988 opset(AADDD, r0) 989 990 case AAND: 991 opset(AOR, r0) 992 opset(AXOR, r0) 993 994 case ABEQ: 995 opset(ABNE, r0) 996 997 case ABLEZ: 998 opset(ABGEZ, r0) 999 opset(ABGEZAL, r0) 1000 opset(ABLTZ, r0) 1001 opset(ABLTZAL, r0) 1002 opset(ABGTZ, r0) 1003 1004 case AMOVB: 1005 opset(AMOVH, r0) 1006 1007 case AMOVBU: 1008 opset(AMOVHU, r0) 1009 1010 case AMUL: 1011 opset(AREM, r0) 1012 opset(AREMU, r0) 1013 opset(ADIVU, r0) 1014 opset(AMULU, r0) 1015 opset(ADIV, r0) 1016 opset(AMADD, r0) 1017 opset(AMSUB, r0) 1018 1019 case AMULV: 1020 opset(ADIVV, r0) 1021 opset(ADIVVU, r0) 1022 opset(AMULVU, r0) 1023 opset(AREMV, r0) 1024 opset(AREMVU, r0) 1025 1026 case ASLL: 1027 opset(ASRL, r0) 1028 opset(ASRA, r0) 1029 opset(AROTR, r0) 1030 1031 case ASLLV: 1032 opset(ASRAV, r0) 1033 opset(ASRLV, r0) 1034 opset(AROTRV, r0) 1035 1036 case ASUB: 1037 opset(ASUBU, r0) 1038 opset(ANOR, r0) 1039 1040 case ASUBV: 1041 opset(ASUBVU, r0) 1042 1043 case ASYSCALL: 1044 opset(ASYNC, r0) 1045 opset(ANOOP, r0) 1046 opset(ATLBP, r0) 1047 opset(ATLBR, r0) 1048 opset(ATLBWI, r0) 1049 opset(ATLBWR, r0) 1050 1051 case ACMPEQF: 1052 opset(ACMPGTF, r0) 1053 opset(ACMPGTD, r0) 1054 opset(ACMPGEF, r0) 1055 opset(ACMPGED, r0) 1056 opset(ACMPEQD, r0) 1057 1058 case ABFPT: 1059 opset(ABFPF, r0) 1060 1061 case AMOVWL: 1062 opset(AMOVWR, r0) 1063 1064 case AMOVVL: 1065 opset(AMOVVR, r0) 1066 1067 case AVMOVB: 1068 opset(AVMOVH, r0) 1069 opset(AVMOVW, r0) 1070 opset(AVMOVD, r0) 1071 1072 case AMOVW, 1073 AMOVD, 1074 AMOVF, 1075 AMOVV, 1076 ABREAK, 1077 ARFE, 1078 AJAL, 1079 AJMP, 1080 AMOVWU, 1081 ALL, 1082 ALLV, 1083 ASC, 1084 ASCV, 1085 ANEGW, 1086 ANEGV, 1087 AWORD, 1088 obj.ANOP, 1089 obj.ATEXT, 1090 obj.AUNDEF, 1091 obj.AFUNCDATA, 1092 obj.APCDATA, 1093 obj.ADUFFZERO, 1094 obj.ADUFFCOPY: 1095 break 1096 1097 case ACMOVN: 1098 opset(ACMOVZ, r0) 1099 1100 case ACMOVT: 1101 opset(ACMOVF, r0) 1102 1103 case ACLO: 1104 opset(ACLZ, r0) 1105 1106 case ATEQ: 1107 opset(ATNE, r0) 1108 1109 case AWSBH: 1110 opset(ASEB, r0) 1111 opset(ASEH, r0) 1112 1113 case ADSBH: 1114 opset(ADSHD, r0) 1115 } 1116 } 1117 } 1118 1119 func OP(x uint32, y uint32) uint32 { 1120 return x<<3 | y<<0 1121 } 1122 1123 func SP(x uint32, y uint32) uint32 { 1124 return x<<29 | y<<26 1125 } 1126 1127 func BCOND(x uint32, y uint32) uint32 { 1128 return x<<19 | y<<16 1129 } 1130 1131 func MMU(x uint32, y uint32) uint32 { 1132 return SP(2, 0) | 16<<21 | x<<3 | y<<0 1133 } 1134 1135 func FPF(x uint32, y uint32) uint32 { 1136 return SP(2, 1) | 16<<21 | x<<3 | y<<0 1137 } 1138 1139 func FPD(x uint32, y uint32) uint32 { 1140 return SP(2, 1) | 17<<21 | x<<3 | y<<0 1141 } 1142 1143 func FPW(x uint32, y uint32) uint32 { 1144 return SP(2, 1) | 20<<21 | x<<3 | y<<0 1145 } 1146 1147 func FPV(x uint32, y uint32) uint32 { 1148 return SP(2, 1) | 21<<21 | x<<3 | y<<0 1149 } 1150 1151 func OP_RRR(op uint32, r1 int16, r2 int16, r3 int16) uint32 { 1152 return op | uint32(r1&31)<<16 | uint32(r2&31)<<21 | uint32(r3&31)<<11 1153 } 1154 1155 func OP_IRR(op uint32, i uint32, r2 int16, r3 int16) uint32 { 1156 return op | i&0xFFFF | uint32(r2&31)<<21 | uint32(r3&31)<<16 1157 } 1158 1159 func OP_SRR(op uint32, s uint32, r2 int16, r3 int16) uint32 { 1160 return op | (s&31)<<6 | uint32(r2&31)<<16 | uint32(r3&31)<<11 1161 } 1162 1163 func OP_FRRR(op uint32, r1 int16, r2 int16, r3 int16) uint32 { 1164 return op | uint32(r1&31)<<16 | uint32(r2&31)<<11 | uint32(r3&31)<<6 1165 } 1166 1167 func OP_JMP(op uint32, i uint32) uint32 { 1168 return op | i&0x3FFFFFF 1169 } 1170 1171 func OP_VI10(op uint32, df uint32, s10 int32, wd uint32, minor uint32) uint32 { 1172 return 0x1e<<26 | (op&7)<<23 | (df&3)<<21 | uint32(s10&0x3FF)<<11 | (wd&31)<<6 | minor&0x3F 1173 } 1174 1175 func OP_VMI10(s10 int32, rs uint32, wd uint32, minor uint32, df uint32) uint32 { 1176 return 0x1e<<26 | uint32(s10&0x3FF)<<16 | (rs&31)<<11 | (wd&31)<<6 | (minor&15)<<2 | df&3 1177 } 1178 1179 func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) { 1180 o1 := uint32(0) 1181 o2 := uint32(0) 1182 o3 := uint32(0) 1183 o4 := uint32(0) 1184 1185 add := AADDU 1186 1187 if c.ctxt.Arch.Family == sys.MIPS64 { 1188 add = AADDVU 1189 } 1190 switch o.type_ { 1191 default: 1192 c.ctxt.Diag("unknown type %d %v", o.type_) 1193 prasm(p) 1194 1195 case 0: /* pseudo ops */ 1196 break 1197 1198 case 1: /* mov r1,r2 ==> OR r1,r0,r2 */ 1199 a := AOR 1200 if p.As == AMOVW && c.ctxt.Arch.Family == sys.MIPS64 { 1201 // on MIPS64, most of the 32-bit instructions have unpredictable behavior, 1202 // but SLL is special that the result is always sign-extended to 64-bit. 1203 a = ASLL 1204 } 1205 o1 = OP_RRR(c.oprrr(a), p.From.Reg, REGZERO, p.To.Reg) 1206 1207 case 2: /* add/sub r1,[r2],r3 */ 1208 r := p.Reg 1209 if p.As == ANEGW || p.As == ANEGV { 1210 r = REGZERO 1211 } 1212 if r == obj.REG_NONE { 1213 r = p.To.Reg 1214 } 1215 o1 = OP_RRR(c.oprrr(p.As), p.From.Reg, r, p.To.Reg) 1216 1217 case 3: /* mov $soreg, r ==> or/add $i,o,r */ 1218 a := add 1219 if o.a1 == C_ANDCON { 1220 a = AOR 1221 } 1222 r := p.From.Reg 1223 if r == obj.REG_NONE { 1224 r = o.param 1225 } 1226 v := c.regoff(&p.From) 1227 o1 = OP_IRR(c.opirr(a), uint32(v), r, p.To.Reg) 1228 1229 case 4: /* add $scon,[r1],r2 */ 1230 r := p.Reg 1231 if r == obj.REG_NONE { 1232 r = p.To.Reg 1233 } 1234 v := c.regoff(&p.From) 1235 o1 = OP_IRR(c.opirr(p.As), uint32(v), r, p.To.Reg) 1236 1237 case 5: /* syscall */ 1238 o1 = c.oprrr(p.As) 1239 1240 case 6: /* beq r1,[r2],sbra */ 1241 v := int32(0) 1242 if p.To.Target() == nil { 1243 v = int32(-4) >> 2 1244 } else { 1245 v = int32(p.To.Target().Pc-p.Pc-4) >> 2 1246 } 1247 if (v<<16)>>16 != v { 1248 c.ctxt.Diag("short branch too far\n%v", p) 1249 } 1250 o1 = OP_IRR(c.opirr(p.As), uint32(v), p.From.Reg, p.Reg) 1251 // for ABFPT and ABFPF only: always fill delay slot with 0 1252 // see comments in func preprocess for details. 1253 o2 = 0 1254 1255 case 7: /* mov r, soreg ==> sw o(r) */ 1256 r := p.To.Reg 1257 if r == obj.REG_NONE { 1258 r = o.param 1259 } 1260 v := c.regoff(&p.To) 1261 o1 = OP_IRR(c.opirr(p.As), uint32(v), r, p.From.Reg) 1262 1263 case 8: /* mov soreg, r ==> lw o(r) */ 1264 r := p.From.Reg 1265 if r == obj.REG_NONE { 1266 r = o.param 1267 } 1268 v := c.regoff(&p.From) 1269 o1 = OP_IRR(c.opirr(-p.As), uint32(v), r, p.To.Reg) 1270 1271 case 9: /* sll r1,[r2],r3 */ 1272 r := p.Reg 1273 if r == obj.REG_NONE { 1274 r = p.To.Reg 1275 } 1276 o1 = OP_RRR(c.oprrr(p.As), r, p.From.Reg, p.To.Reg) 1277 1278 case 10: /* add $con,[r1],r2 ==> mov $con, t; add t,[r1],r2 */ 1279 v := c.regoff(&p.From) 1280 a := AOR 1281 if v < 0 { 1282 a = AADDU 1283 } 1284 o1 = OP_IRR(c.opirr(a), uint32(v), obj.REG_NONE, REGTMP) 1285 r := p.Reg 1286 if r == obj.REG_NONE { 1287 r = p.To.Reg 1288 } 1289 o2 = OP_RRR(c.oprrr(p.As), REGTMP, r, p.To.Reg) 1290 1291 case 11: /* jmp lbra */ 1292 v := int32(0) 1293 if c.aclass(&p.To) == C_SBRA && p.To.Sym == nil && p.As == AJMP { 1294 // use PC-relative branch for short branches 1295 // BEQ R0, R0, sbra 1296 if p.To.Target() == nil { 1297 v = int32(-4) >> 2 1298 } else { 1299 v = int32(p.To.Target().Pc-p.Pc-4) >> 2 1300 } 1301 if (v<<16)>>16 == v { 1302 o1 = OP_IRR(c.opirr(ABEQ), uint32(v), REGZERO, REGZERO) 1303 break 1304 } 1305 } 1306 if p.To.Target() == nil { 1307 v = int32(p.Pc) >> 2 1308 } else { 1309 v = int32(p.To.Target().Pc) >> 2 1310 } 1311 o1 = OP_JMP(c.opirr(p.As), uint32(v)) 1312 if p.To.Sym == nil { 1313 p.To.Sym = c.cursym.Func().Text.From.Sym 1314 p.To.Offset = p.To.Target().Pc 1315 } 1316 rel := obj.Addrel(c.cursym) 1317 rel.Off = int32(c.pc) 1318 rel.Siz = 4 1319 rel.Sym = p.To.Sym 1320 rel.Add = p.To.Offset 1321 if p.As == AJAL { 1322 rel.Type = objabi.R_CALLMIPS 1323 } else { 1324 rel.Type = objabi.R_JMPMIPS 1325 } 1326 1327 case 12: /* movbs r,r */ 1328 // NOTE: this case does not use REGTMP. If it ever does, 1329 // remove the NOTUSETMP flag in optab. 1330 v := 16 1331 if p.As == AMOVB { 1332 v = 24 1333 } 1334 o1 = OP_SRR(c.opirr(ASLL), uint32(v), p.From.Reg, p.To.Reg) 1335 o2 = OP_SRR(c.opirr(ASRA), uint32(v), p.To.Reg, p.To.Reg) 1336 1337 case 13: /* movbu r,r */ 1338 if p.As == AMOVBU { 1339 o1 = OP_IRR(c.opirr(AAND), uint32(0xff), p.From.Reg, p.To.Reg) 1340 } else { 1341 o1 = OP_IRR(c.opirr(AAND), uint32(0xffff), p.From.Reg, p.To.Reg) 1342 } 1343 1344 case 14: /* movwu r,r */ 1345 // NOTE: this case does not use REGTMP. If it ever does, 1346 // remove the NOTUSETMP flag in optab. 1347 o1 = OP_SRR(c.opirr(-ASLLV), 0, p.From.Reg, p.To.Reg) 1348 o2 = OP_SRR(c.opirr(-ASRLV), 0, p.To.Reg, p.To.Reg) 1349 1350 case 15: /* teq $c r,r */ 1351 r := p.Reg 1352 if r == obj.REG_NONE { 1353 r = REGZERO 1354 } 1355 v := c.regoff(&p.From) 1356 /* only use 10 bits of trap code */ 1357 o1 = OP_IRR(c.opirr(p.As), (uint32(v)&0x3FF)<<6, r, p.To.Reg) 1358 1359 case 16: /* sll $c,[r1],r2 */ 1360 r := p.Reg 1361 if r == obj.REG_NONE { 1362 r = p.To.Reg 1363 } 1364 v := c.regoff(&p.From) 1365 1366 /* OP_SRR will use only the low 5 bits of the shift value */ 1367 if v >= 32 && vshift(p.As) { 1368 o1 = OP_SRR(c.opirr(-p.As), uint32(v-32), r, p.To.Reg) 1369 } else { 1370 o1 = OP_SRR(c.opirr(p.As), uint32(v), r, p.To.Reg) 1371 } 1372 1373 case 17: 1374 o1 = OP_RRR(c.oprrr(p.As), REGZERO, p.From.Reg, p.To.Reg) 1375 1376 case 18: /* jmp [r1],0(r2) */ 1377 r := p.Reg 1378 if r == obj.REG_NONE { 1379 r = o.param 1380 } 1381 o1 = OP_RRR(c.oprrr(p.As), obj.REG_NONE, p.To.Reg, r) 1382 if p.As == obj.ACALL { 1383 rel := obj.Addrel(c.cursym) 1384 rel.Off = int32(c.pc) 1385 rel.Siz = 0 1386 rel.Type = objabi.R_CALLIND 1387 } 1388 1389 case 19: /* mov $lcon,r ==> lu+or */ 1390 // NOTE: this case does not use REGTMP. If it ever does, 1391 // remove the NOTUSETMP flag in optab. 1392 v := c.regoff(&p.From) 1393 o1 = OP_IRR(c.opirr(ALUI), uint32(v>>16), REGZERO, p.To.Reg) 1394 o2 = OP_IRR(c.opirr(AOR), uint32(v), p.To.Reg, p.To.Reg) 1395 1396 case 20: /* mov lo/hi,r */ 1397 a := OP(2, 0) /* mfhi */ 1398 if p.From.Reg == REG_LO { 1399 a = OP(2, 2) /* mflo */ 1400 } 1401 o1 = OP_RRR(a, REGZERO, REGZERO, p.To.Reg) 1402 1403 case 21: /* mov r,lo/hi */ 1404 a := OP(2, 1) /* mthi */ 1405 if p.To.Reg == REG_LO { 1406 a = OP(2, 3) /* mtlo */ 1407 } 1408 o1 = OP_RRR(a, REGZERO, p.From.Reg, REGZERO) 1409 1410 case 22: /* mul r1,r2 [r3]*/ 1411 if p.To.Reg != obj.REG_NONE { 1412 r := p.Reg 1413 if r == obj.REG_NONE { 1414 r = p.To.Reg 1415 } 1416 a := SP(3, 4) | 2 /* mul */ 1417 o1 = OP_RRR(a, p.From.Reg, r, p.To.Reg) 1418 } else { 1419 o1 = OP_RRR(c.oprrr(p.As), p.From.Reg, p.Reg, REGZERO) 1420 } 1421 1422 case 23: /* add $lcon,r1,r2 ==> lu+or+add */ 1423 v := c.regoff(&p.From) 1424 o1 = OP_IRR(c.opirr(ALUI), uint32(v>>16), REGZERO, REGTMP) 1425 o2 = OP_IRR(c.opirr(AOR), uint32(v), REGTMP, REGTMP) 1426 r := p.Reg 1427 if r == obj.REG_NONE { 1428 r = p.To.Reg 1429 } 1430 o3 = OP_RRR(c.oprrr(p.As), REGTMP, r, p.To.Reg) 1431 1432 case 24: /* mov $ucon,r ==> lu r */ 1433 v := c.regoff(&p.From) 1434 o1 = OP_IRR(c.opirr(ALUI), uint32(v>>16), REGZERO, p.To.Reg) 1435 1436 case 25: /* add/and $ucon,[r1],r2 ==> lu $con,t; add t,[r1],r2 */ 1437 v := c.regoff(&p.From) 1438 o1 = OP_IRR(c.opirr(ALUI), uint32(v>>16), REGZERO, REGTMP) 1439 r := p.Reg 1440 if r == obj.REG_NONE { 1441 r = p.To.Reg 1442 } 1443 o2 = OP_RRR(c.oprrr(p.As), REGTMP, r, p.To.Reg) 1444 1445 case 26: /* mov $lsext/auto/oreg,r ==> lu+or+add */ 1446 v := c.regoff(&p.From) 1447 o1 = OP_IRR(c.opirr(ALUI), uint32(v>>16), REGZERO, REGTMP) 1448 o2 = OP_IRR(c.opirr(AOR), uint32(v), REGTMP, REGTMP) 1449 r := p.From.Reg 1450 if r == obj.REG_NONE { 1451 r = o.param 1452 } 1453 o3 = OP_RRR(c.oprrr(add), REGTMP, r, p.To.Reg) 1454 1455 case 27: /* mov [sl]ext/auto/oreg,fr ==> lwc1 o(r) */ 1456 a := -AMOVF 1457 if p.As == AMOVD { 1458 a = -AMOVD 1459 } 1460 r := p.From.Reg 1461 if r == obj.REG_NONE { 1462 r = o.param 1463 } 1464 v := c.regoff(&p.From) 1465 switch o.size { 1466 case 12: 1467 o1 = OP_IRR(c.opirr(ALUI), uint32((v+1<<15)>>16), REGZERO, REGTMP) 1468 o2 = OP_RRR(c.oprrr(add), r, REGTMP, REGTMP) 1469 o3 = OP_IRR(c.opirr(a), uint32(v), REGTMP, p.To.Reg) 1470 1471 case 4: 1472 o1 = OP_IRR(c.opirr(a), uint32(v), r, p.To.Reg) 1473 } 1474 1475 case 28: /* mov fr,[sl]ext/auto/oreg ==> swc1 o(r) */ 1476 a := AMOVF 1477 if p.As == AMOVD { 1478 a = AMOVD 1479 } 1480 r := p.To.Reg 1481 if r == obj.REG_NONE { 1482 r = o.param 1483 } 1484 v := c.regoff(&p.To) 1485 switch o.size { 1486 case 12: 1487 o1 = OP_IRR(c.opirr(ALUI), uint32((v+1<<15)>>16), REGZERO, REGTMP) 1488 o2 = OP_RRR(c.oprrr(add), r, REGTMP, REGTMP) 1489 o3 = OP_IRR(c.opirr(a), uint32(v), REGTMP, p.From.Reg) 1490 1491 case 4: 1492 o1 = OP_IRR(c.opirr(a), uint32(v), r, p.From.Reg) 1493 } 1494 1495 case 30: /* movw r,fr */ 1496 a := SP(2, 1) | (4 << 21) /* mtc1 */ 1497 o1 = OP_RRR(a, p.From.Reg, obj.REG_NONE, p.To.Reg) 1498 1499 case 31: /* movw fr,r */ 1500 a := SP(2, 1) | (0 << 21) /* mtc1 */ 1501 o1 = OP_RRR(a, p.To.Reg, obj.REG_NONE, p.From.Reg) 1502 1503 case 32: /* fadd fr1,[fr2],fr3 */ 1504 r := p.Reg 1505 if r == obj.REG_NONE { 1506 r = p.To.Reg 1507 } 1508 o1 = OP_FRRR(c.oprrr(p.As), p.From.Reg, r, p.To.Reg) 1509 1510 case 33: /* fabs fr1, fr3 */ 1511 o1 = OP_FRRR(c.oprrr(p.As), obj.REG_NONE, p.From.Reg, p.To.Reg) 1512 1513 case 34: /* mov $con,fr ==> or/add $i,t; mov t,fr */ 1514 a := AADDU 1515 if o.a1 == C_ANDCON { 1516 a = AOR 1517 } 1518 v := c.regoff(&p.From) 1519 o1 = OP_IRR(c.opirr(a), uint32(v), obj.REG_NONE, REGTMP) 1520 o2 = OP_RRR(SP(2, 1)|(4<<21), REGTMP, obj.REG_NONE, p.To.Reg) /* mtc1 */ 1521 1522 case 35: /* mov r,lext/auto/oreg ==> sw o(REGTMP) */ 1523 r := p.To.Reg 1524 if r == obj.REG_NONE { 1525 r = o.param 1526 } 1527 v := c.regoff(&p.To) 1528 o1 = OP_IRR(c.opirr(ALUI), uint32((v+1<<15)>>16), REGZERO, REGTMP) 1529 o2 = OP_RRR(c.oprrr(add), r, REGTMP, REGTMP) 1530 o3 = OP_IRR(c.opirr(p.As), uint32(v), REGTMP, p.From.Reg) 1531 1532 case 36: /* mov lext/auto/oreg,r ==> lw o(REGTMP) */ 1533 r := p.From.Reg 1534 if r == obj.REG_NONE { 1535 r = o.param 1536 } 1537 v := c.regoff(&p.From) 1538 o1 = OP_IRR(c.opirr(ALUI), uint32((v+1<<15)>>16), REGZERO, REGTMP) 1539 o2 = OP_RRR(c.oprrr(add), r, REGTMP, REGTMP) 1540 o3 = OP_IRR(c.opirr(-p.As), uint32(v), REGTMP, p.To.Reg) 1541 1542 case 37: /* movw r,mr */ 1543 a := SP(2, 0) | (4 << 21) /* mtc0 */ 1544 if p.As == AMOVV { 1545 a = SP(2, 0) | (5 << 21) /* dmtc0 */ 1546 } 1547 o1 = OP_RRR(a, p.From.Reg, obj.REG_NONE, p.To.Reg) 1548 1549 case 38: /* movw mr,r */ 1550 a := SP(2, 0) | (0 << 21) /* mfc0 */ 1551 if p.As == AMOVV { 1552 a = SP(2, 0) | (1 << 21) /* dmfc0 */ 1553 } 1554 o1 = OP_RRR(a, p.To.Reg, obj.REG_NONE, p.From.Reg) 1555 1556 case 40: /* word */ 1557 o1 = uint32(c.regoff(&p.From)) 1558 1559 case 41: /* movw f,fcr */ 1560 o1 = OP_RRR(SP(2, 1)|(6<<21), p.From.Reg, obj.REG_NONE, p.To.Reg) /* mtcc1 */ 1561 1562 case 42: /* movw fcr,r */ 1563 o1 = OP_RRR(SP(2, 1)|(2<<21), p.To.Reg, obj.REG_NONE, p.From.Reg) /* mfcc1 */ 1564 1565 case 47: /* movv r,fr */ 1566 a := SP(2, 1) | (5 << 21) /* dmtc1 */ 1567 o1 = OP_RRR(a, p.From.Reg, obj.REG_NONE, p.To.Reg) 1568 1569 case 48: /* movv fr,r */ 1570 a := SP(2, 1) | (1 << 21) /* dmtc1 */ 1571 o1 = OP_RRR(a, p.To.Reg, obj.REG_NONE, p.From.Reg) 1572 1573 case 49: /* undef */ 1574 o1 = 52 /* trap -- teq r0, r0 */ 1575 1576 /* relocation operations */ 1577 case 50: /* mov r,addr ==> lu + add REGSB, REGTMP + sw o(REGTMP) */ 1578 o1 = OP_IRR(c.opirr(ALUI), 0, REGZERO, REGTMP) 1579 rel := obj.Addrel(c.cursym) 1580 rel.Off = int32(c.pc) 1581 rel.Siz = 4 1582 rel.Sym = p.To.Sym 1583 rel.Add = p.To.Offset 1584 rel.Type = objabi.R_ADDRMIPSU 1585 o2 = OP_IRR(c.opirr(p.As), 0, REGTMP, p.From.Reg) 1586 rel2 := obj.Addrel(c.cursym) 1587 rel2.Off = int32(c.pc + 4) 1588 rel2.Siz = 4 1589 rel2.Sym = p.To.Sym 1590 rel2.Add = p.To.Offset 1591 rel2.Type = objabi.R_ADDRMIPS 1592 1593 if o.size == 12 { 1594 o3 = o2 1595 o2 = OP_RRR(c.oprrr(AADDVU), REGSB, REGTMP, REGTMP) 1596 rel2.Off += 4 1597 } 1598 1599 case 51: /* mov addr,r ==> lu + add REGSB, REGTMP + lw o(REGTMP) */ 1600 o1 = OP_IRR(c.opirr(ALUI), 0, REGZERO, REGTMP) 1601 rel := obj.Addrel(c.cursym) 1602 rel.Off = int32(c.pc) 1603 rel.Siz = 4 1604 rel.Sym = p.From.Sym 1605 rel.Add = p.From.Offset 1606 rel.Type = objabi.R_ADDRMIPSU 1607 o2 = OP_IRR(c.opirr(-p.As), 0, REGTMP, p.To.Reg) 1608 rel2 := obj.Addrel(c.cursym) 1609 rel2.Off = int32(c.pc + 4) 1610 rel2.Siz = 4 1611 rel2.Sym = p.From.Sym 1612 rel2.Add = p.From.Offset 1613 rel2.Type = objabi.R_ADDRMIPS 1614 1615 if o.size == 12 { 1616 o3 = o2 1617 o2 = OP_RRR(c.oprrr(AADDVU), REGSB, REGTMP, REGTMP) 1618 rel2.Off += 4 1619 } 1620 1621 case 52: /* mov $lext, r ==> lu + add REGSB, r + add */ 1622 // NOTE: this case does not use REGTMP. If it ever does, 1623 // remove the NOTUSETMP flag in optab. 1624 o1 = OP_IRR(c.opirr(ALUI), 0, REGZERO, p.To.Reg) 1625 rel := obj.Addrel(c.cursym) 1626 rel.Off = int32(c.pc) 1627 rel.Siz = 4 1628 rel.Sym = p.From.Sym 1629 rel.Add = p.From.Offset 1630 rel.Type = objabi.R_ADDRMIPSU 1631 o2 = OP_IRR(c.opirr(add), 0, p.To.Reg, p.To.Reg) 1632 rel2 := obj.Addrel(c.cursym) 1633 rel2.Off = int32(c.pc + 4) 1634 rel2.Siz = 4 1635 rel2.Sym = p.From.Sym 1636 rel2.Add = p.From.Offset 1637 rel2.Type = objabi.R_ADDRMIPS 1638 1639 if o.size == 12 { 1640 o3 = o2 1641 o2 = OP_RRR(c.oprrr(AADDVU), REGSB, p.To.Reg, p.To.Reg) 1642 rel2.Off += 4 1643 } 1644 1645 case 53: /* mov r, tlsvar ==> rdhwr + sw o(r3) */ 1646 // clobbers R3 ! 1647 // load thread pointer with RDHWR, R3 is used for fast kernel emulation on Linux 1648 // NOTE: this case does not use REGTMP. If it ever does, 1649 // remove the NOTUSETMP flag in optab. 1650 o1 = (037<<26 + 073) | (29 << 11) | (3 << 16) // rdhwr $29, r3 1651 o2 = OP_IRR(c.opirr(p.As), 0, REG_R3, p.From.Reg) 1652 rel := obj.Addrel(c.cursym) 1653 rel.Off = int32(c.pc + 4) 1654 rel.Siz = 4 1655 rel.Sym = p.To.Sym 1656 rel.Add = p.To.Offset 1657 rel.Type = objabi.R_ADDRMIPSTLS 1658 1659 case 54: /* mov tlsvar, r ==> rdhwr + lw o(r3) */ 1660 // clobbers R3 ! 1661 // NOTE: this case does not use REGTMP. If it ever does, 1662 // remove the NOTUSETMP flag in optab. 1663 o1 = (037<<26 + 073) | (29 << 11) | (3 << 16) // rdhwr $29, r3 1664 o2 = OP_IRR(c.opirr(-p.As), 0, REG_R3, p.To.Reg) 1665 rel := obj.Addrel(c.cursym) 1666 rel.Off = int32(c.pc + 4) 1667 rel.Siz = 4 1668 rel.Sym = p.From.Sym 1669 rel.Add = p.From.Offset 1670 rel.Type = objabi.R_ADDRMIPSTLS 1671 1672 case 55: /* mov $tlsvar, r ==> rdhwr + add */ 1673 // clobbers R3 ! 1674 // NOTE: this case does not use REGTMP. If it ever does, 1675 // remove the NOTUSETMP flag in optab. 1676 o1 = (037<<26 + 073) | (29 << 11) | (3 << 16) // rdhwr $29, r3 1677 o2 = OP_IRR(c.opirr(add), 0, REG_R3, p.To.Reg) 1678 rel := obj.Addrel(c.cursym) 1679 rel.Off = int32(c.pc + 4) 1680 rel.Siz = 4 1681 rel.Sym = p.From.Sym 1682 rel.Add = p.From.Offset 1683 rel.Type = objabi.R_ADDRMIPSTLS 1684 1685 case 56: /* vmov{b,h,w,d} $scon, wr */ 1686 1687 v := c.regoff(&p.From) 1688 o1 = OP_VI10(110, c.twobitdf(p.As), v, uint32(p.To.Reg), 7) 1689 1690 case 57: /* vld $soreg, wr */ 1691 v := c.lsoffset(p.As, c.regoff(&p.From)) 1692 o1 = OP_VMI10(v, uint32(p.From.Reg), uint32(p.To.Reg), 8, c.twobitdf(p.As)) 1693 1694 case 58: /* vst wr, $soreg */ 1695 v := c.lsoffset(p.As, c.regoff(&p.To)) 1696 o1 = OP_VMI10(v, uint32(p.To.Reg), uint32(p.From.Reg), 9, c.twobitdf(p.As)) 1697 1698 case 59: 1699 o1 = OP_RRR(c.oprrr(p.As), p.From.Reg, REGZERO, p.To.Reg) 1700 } 1701 1702 out[0] = o1 1703 out[1] = o2 1704 out[2] = o3 1705 out[3] = o4 1706 } 1707 1708 func (c *ctxt0) vregoff(a *obj.Addr) int64 { 1709 c.instoffset = 0 1710 c.aclass(a) 1711 return c.instoffset 1712 } 1713 1714 func (c *ctxt0) regoff(a *obj.Addr) int32 { 1715 return int32(c.vregoff(a)) 1716 } 1717 1718 func (c *ctxt0) oprrr(a obj.As) uint32 { 1719 switch a { 1720 case AADD: 1721 return OP(4, 0) 1722 case AADDU: 1723 return OP(4, 1) 1724 case ASGT: 1725 return OP(5, 2) 1726 case ASGTU: 1727 return OP(5, 3) 1728 case AAND: 1729 return OP(4, 4) 1730 case AOR: 1731 return OP(4, 5) 1732 case AXOR: 1733 return OP(4, 6) 1734 case ASUB: 1735 return OP(4, 2) 1736 case ASUBU, ANEGW: 1737 return OP(4, 3) 1738 case ANOR: 1739 return OP(4, 7) 1740 case ASLL: 1741 return OP(0, 4) 1742 case ASRL: 1743 return OP(0, 6) 1744 case ASRA: 1745 return OP(0, 7) 1746 case AROTR: 1747 return OP(8, 6) 1748 case ASLLV: 1749 return OP(2, 4) 1750 case ASRLV: 1751 return OP(2, 6) 1752 case ASRAV: 1753 return OP(2, 7) 1754 case AROTRV: 1755 return OP(10, 6) 1756 case AADDV: 1757 return OP(5, 4) 1758 case AADDVU: 1759 return OP(5, 5) 1760 case ASUBV: 1761 return OP(5, 6) 1762 case ASUBVU, ANEGV: 1763 return OP(5, 7) 1764 case AREM, 1765 ADIV: 1766 return OP(3, 2) 1767 case AREMU, 1768 ADIVU: 1769 return OP(3, 3) 1770 case AMUL: 1771 return OP(3, 0) 1772 case AMULU: 1773 return OP(3, 1) 1774 case AREMV, 1775 ADIVV: 1776 return OP(3, 6) 1777 case AREMVU, 1778 ADIVVU: 1779 return OP(3, 7) 1780 case AMULV: 1781 return OP(3, 4) 1782 case AMULVU: 1783 return OP(3, 5) 1784 1785 case AJMP: 1786 return OP(1, 0) 1787 case AJAL: 1788 return OP(1, 1) 1789 1790 case ABREAK: 1791 return OP(1, 5) 1792 case ASYSCALL: 1793 return OP(1, 4) 1794 case ATLBP: 1795 return MMU(1, 0) 1796 case ATLBR: 1797 return MMU(0, 1) 1798 case ATLBWI: 1799 return MMU(0, 2) 1800 case ATLBWR: 1801 return MMU(0, 6) 1802 case ARFE: 1803 return MMU(2, 0) 1804 1805 case ADIVF: 1806 return FPF(0, 3) 1807 case ADIVD: 1808 return FPD(0, 3) 1809 case AMULF: 1810 return FPF(0, 2) 1811 case AMULD: 1812 return FPD(0, 2) 1813 case ASUBF: 1814 return FPF(0, 1) 1815 case ASUBD: 1816 return FPD(0, 1) 1817 case AADDF: 1818 return FPF(0, 0) 1819 case AADDD: 1820 return FPD(0, 0) 1821 case ATRUNCFV: 1822 return FPF(1, 1) 1823 case ATRUNCDV: 1824 return FPD(1, 1) 1825 case ATRUNCFW: 1826 return FPF(1, 5) 1827 case ATRUNCDW: 1828 return FPD(1, 5) 1829 case AMOVFV: 1830 return FPF(4, 5) 1831 case AMOVDV: 1832 return FPD(4, 5) 1833 case AMOVVF: 1834 return FPV(4, 0) 1835 case AMOVVD: 1836 return FPV(4, 1) 1837 case AMOVFW: 1838 return FPF(4, 4) 1839 case AMOVDW: 1840 return FPD(4, 4) 1841 case AMOVWF: 1842 return FPW(4, 0) 1843 case AMOVDF: 1844 return FPD(4, 0) 1845 case AMOVWD: 1846 return FPW(4, 1) 1847 case AMOVFD: 1848 return FPF(4, 1) 1849 case AABSF: 1850 return FPF(0, 5) 1851 case AABSD: 1852 return FPD(0, 5) 1853 case AMOVF: 1854 return FPF(0, 6) 1855 case AMOVD: 1856 return FPD(0, 6) 1857 case ANEGF: 1858 return FPF(0, 7) 1859 case ANEGD: 1860 return FPD(0, 7) 1861 case ACMPEQF: 1862 return FPF(6, 2) 1863 case ACMPEQD: 1864 return FPD(6, 2) 1865 case ACMPGTF: 1866 return FPF(7, 4) 1867 case ACMPGTD: 1868 return FPD(7, 4) 1869 case ACMPGEF: 1870 return FPF(7, 6) 1871 case ACMPGED: 1872 return FPD(7, 6) 1873 1874 case ASQRTF: 1875 return FPF(0, 4) 1876 case ASQRTD: 1877 return FPD(0, 4) 1878 1879 case ASYNC: 1880 return OP(1, 7) 1881 case ANOOP: 1882 return 0 1883 1884 case ACMOVN: 1885 return OP(1, 3) 1886 case ACMOVZ: 1887 return OP(1, 2) 1888 case ACMOVT: 1889 return OP(0, 1) | (1 << 16) 1890 case ACMOVF: 1891 return OP(0, 1) | (0 << 16) 1892 case ACLO: 1893 return SP(3, 4) | OP(4, 1) 1894 case ACLZ: 1895 return SP(3, 4) | OP(4, 0) 1896 case AMADD: 1897 return SP(3, 4) | OP(0, 0) 1898 case AMSUB: 1899 return SP(3, 4) | OP(0, 4) 1900 case AWSBH: 1901 return SP(3, 7) | OP(20, 0) 1902 case ADSBH: 1903 return SP(3, 7) | OP(20, 4) 1904 case ADSHD: 1905 return SP(3, 7) | OP(44, 4) 1906 case ASEB: 1907 return SP(3, 7) | OP(132, 0) 1908 case ASEH: 1909 return SP(3, 7) | OP(196, 0) 1910 } 1911 1912 if a < 0 { 1913 c.ctxt.Diag("bad rrr opcode -%v", -a) 1914 } else { 1915 c.ctxt.Diag("bad rrr opcode %v", a) 1916 } 1917 return 0 1918 } 1919 1920 func (c *ctxt0) opirr(a obj.As) uint32 { 1921 switch a { 1922 case AADD: 1923 return SP(1, 0) 1924 case AADDU: 1925 return SP(1, 1) 1926 case ASGT: 1927 return SP(1, 2) 1928 case ASGTU: 1929 return SP(1, 3) 1930 case AAND: 1931 return SP(1, 4) 1932 case AOR: 1933 return SP(1, 5) 1934 case AXOR: 1935 return SP(1, 6) 1936 case ALUI: 1937 return SP(1, 7) 1938 case ASLL: 1939 return OP(0, 0) 1940 case ASRL: 1941 return OP(0, 2) 1942 case ASRA: 1943 return OP(0, 3) 1944 case AROTR: 1945 return OP(0, 2) | 1<<21 1946 case AADDV: 1947 return SP(3, 0) 1948 case AADDVU: 1949 return SP(3, 1) 1950 1951 case AJMP: 1952 return SP(0, 2) 1953 case AJAL, 1954 obj.ADUFFZERO, 1955 obj.ADUFFCOPY: 1956 return SP(0, 3) 1957 case ABEQ: 1958 return SP(0, 4) 1959 case -ABEQ: 1960 return SP(2, 4) /* likely */ 1961 case ABNE: 1962 return SP(0, 5) 1963 case -ABNE: 1964 return SP(2, 5) /* likely */ 1965 case ABGEZ: 1966 return SP(0, 1) | BCOND(0, 1) 1967 case -ABGEZ: 1968 return SP(0, 1) | BCOND(0, 3) /* likely */ 1969 case ABGEZAL: 1970 return SP(0, 1) | BCOND(2, 1) 1971 case -ABGEZAL: 1972 return SP(0, 1) | BCOND(2, 3) /* likely */ 1973 case ABGTZ: 1974 return SP(0, 7) 1975 case -ABGTZ: 1976 return SP(2, 7) /* likely */ 1977 case ABLEZ: 1978 return SP(0, 6) 1979 case -ABLEZ: 1980 return SP(2, 6) /* likely */ 1981 case ABLTZ: 1982 return SP(0, 1) | BCOND(0, 0) 1983 case -ABLTZ: 1984 return SP(0, 1) | BCOND(0, 2) /* likely */ 1985 case ABLTZAL: 1986 return SP(0, 1) | BCOND(2, 0) 1987 case -ABLTZAL: 1988 return SP(0, 1) | BCOND(2, 2) /* likely */ 1989 case ABFPT: 1990 return SP(2, 1) | (257 << 16) 1991 case -ABFPT: 1992 return SP(2, 1) | (259 << 16) /* likely */ 1993 case ABFPF: 1994 return SP(2, 1) | (256 << 16) 1995 case -ABFPF: 1996 return SP(2, 1) | (258 << 16) /* likely */ 1997 1998 case AMOVB, 1999 AMOVBU: 2000 return SP(5, 0) 2001 case AMOVH, 2002 AMOVHU: 2003 return SP(5, 1) 2004 case AMOVW, 2005 AMOVWU: 2006 return SP(5, 3) 2007 case AMOVV: 2008 return SP(7, 7) 2009 case AMOVF: 2010 return SP(7, 1) 2011 case AMOVD: 2012 return SP(7, 5) 2013 case AMOVWL: 2014 return SP(5, 2) 2015 case AMOVWR: 2016 return SP(5, 6) 2017 case AMOVVL: 2018 return SP(5, 4) 2019 case AMOVVR: 2020 return SP(5, 5) 2021 2022 case ABREAK: 2023 return SP(5, 7) 2024 2025 case -AMOVWL: 2026 return SP(4, 2) 2027 case -AMOVWR: 2028 return SP(4, 6) 2029 case -AMOVVL: 2030 return SP(3, 2) 2031 case -AMOVVR: 2032 return SP(3, 3) 2033 case -AMOVB: 2034 return SP(4, 0) 2035 case -AMOVBU: 2036 return SP(4, 4) 2037 case -AMOVH: 2038 return SP(4, 1) 2039 case -AMOVHU: 2040 return SP(4, 5) 2041 case -AMOVW: 2042 return SP(4, 3) 2043 case -AMOVWU: 2044 return SP(4, 7) 2045 case -AMOVV: 2046 return SP(6, 7) 2047 case -AMOVF: 2048 return SP(6, 1) 2049 case -AMOVD: 2050 return SP(6, 5) 2051 2052 case ASLLV: 2053 return OP(7, 0) 2054 case ASRLV: 2055 return OP(7, 2) 2056 case ASRAV: 2057 return OP(7, 3) 2058 case AROTRV: 2059 return OP(7, 2) | 1<<21 2060 case -ASLLV: 2061 return OP(7, 4) 2062 case -ASRLV: 2063 return OP(7, 6) 2064 case -ASRAV: 2065 return OP(7, 7) 2066 case -AROTRV: 2067 return OP(7, 6) | 1<<21 2068 2069 case ATEQ: 2070 return OP(6, 4) 2071 case ATNE: 2072 return OP(6, 6) 2073 case -ALL: 2074 return SP(6, 0) 2075 case -ALLV: 2076 return SP(6, 4) 2077 case ASC: 2078 return SP(7, 0) 2079 case ASCV: 2080 return SP(7, 4) 2081 } 2082 2083 if a < 0 { 2084 c.ctxt.Diag("bad irr opcode -%v", -a) 2085 } else { 2086 c.ctxt.Diag("bad irr opcode %v", a) 2087 } 2088 return 0 2089 } 2090 2091 func vshift(a obj.As) bool { 2092 switch a { 2093 case ASLLV, 2094 ASRLV, 2095 ASRAV, 2096 AROTRV: 2097 return true 2098 } 2099 return false 2100 } 2101 2102 // MSA Two-bit Data Format Field Encoding 2103 func (c *ctxt0) twobitdf(a obj.As) uint32 { 2104 switch a { 2105 case AVMOVB: 2106 return 0 2107 case AVMOVH: 2108 return 1 2109 case AVMOVW: 2110 return 2 2111 case AVMOVD: 2112 return 3 2113 default: 2114 c.ctxt.Diag("unsupported data format %v", a) 2115 } 2116 return 0 2117 } 2118 2119 // MSA Load/Store offset have to be multiple of size of data format 2120 func (c *ctxt0) lsoffset(a obj.As, o int32) int32 { 2121 var mod int32 2122 switch a { 2123 case AVMOVB: 2124 mod = 1 2125 case AVMOVH: 2126 mod = 2 2127 case AVMOVW: 2128 mod = 4 2129 case AVMOVD: 2130 mod = 8 2131 default: 2132 c.ctxt.Diag("unsupported instruction:%v", a) 2133 } 2134 2135 if o%mod != 0 { 2136 c.ctxt.Diag("invalid offset for %v: %d is not a multiple of %d", a, o, mod) 2137 } 2138 2139 return o / mod 2140 }