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