github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/internal/obj/arm/asm5.go (about)

     1  // Inferno utils/5l/span.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/span.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors. All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  package arm
    32  
    33  import (
    34  	"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  			t := int(immaddr(int32(ctxt.Instoffset)))
  1030  			if t != 0 {
  1031  				if immhalf(int32(ctxt.Instoffset)) {
  1032  					if immfloat(int32(t)) {
  1033  						return C_HFAUTO
  1034  					}
  1035  					return C_HAUTO
  1036  				}
  1037  
  1038  				if immfloat(int32(t)) {
  1039  					return C_FAUTO
  1040  				}
  1041  				return C_SAUTO
  1042  			}
  1043  
  1044  			return C_LAUTO
  1045  
  1046  		case obj.NAME_PARAM:
  1047  			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
  1048  			t := int(immaddr(int32(ctxt.Instoffset)))
  1049  			if t != 0 {
  1050  				if immhalf(int32(ctxt.Instoffset)) {
  1051  					if immfloat(int32(t)) {
  1052  						return C_HFAUTO
  1053  					}
  1054  					return C_HAUTO
  1055  				}
  1056  
  1057  				if immfloat(int32(t)) {
  1058  					return C_FAUTO
  1059  				}
  1060  				return C_SAUTO
  1061  			}
  1062  
  1063  			return C_LAUTO
  1064  
  1065  		case obj.NAME_NONE:
  1066  			ctxt.Instoffset = a.Offset
  1067  			t := int(immaddr(int32(ctxt.Instoffset)))
  1068  			if t != 0 {
  1069  				if immhalf(int32(ctxt.Instoffset)) { /* n.b. that it will also satisfy immrot */
  1070  					if immfloat(int32(t)) {
  1071  						return C_HFOREG
  1072  					}
  1073  					return C_HOREG
  1074  				}
  1075  
  1076  				if immfloat(int32(t)) {
  1077  					return C_FOREG /* n.b. that it will also satisfy immrot */
  1078  				}
  1079  				t := int(immrot(uint32(ctxt.Instoffset)))
  1080  				if t != 0 {
  1081  					return C_SROREG
  1082  				}
  1083  				if immhalf(int32(ctxt.Instoffset)) {
  1084  					return C_HOREG
  1085  				}
  1086  				return C_SOREG
  1087  			}
  1088  
  1089  			t = int(immrot(uint32(ctxt.Instoffset)))
  1090  			if t != 0 {
  1091  				return C_ROREG
  1092  			}
  1093  			return C_LOREG
  1094  		}
  1095  
  1096  		return C_GOK
  1097  
  1098  	case obj.TYPE_FCONST:
  1099  		if chipzero5(ctxt, a.Val.(float64)) >= 0 {
  1100  			return C_ZFCON
  1101  		}
  1102  		if chipfloat5(ctxt, a.Val.(float64)) >= 0 {
  1103  			return C_SFCON
  1104  		}
  1105  		return C_LFCON
  1106  
  1107  	case obj.TYPE_TEXTSIZE:
  1108  		return C_TEXTSIZE
  1109  
  1110  	case obj.TYPE_CONST,
  1111  		obj.TYPE_ADDR:
  1112  		switch a.Name {
  1113  		case obj.NAME_NONE:
  1114  			ctxt.Instoffset = a.Offset
  1115  			if a.Reg != 0 {
  1116  				return aconsize(ctxt)
  1117  			}
  1118  
  1119  			t := int(immrot(uint32(ctxt.Instoffset)))
  1120  			if t != 0 {
  1121  				return C_RCON
  1122  			}
  1123  			t = int(immrot(^uint32(ctxt.Instoffset)))
  1124  			if t != 0 {
  1125  				return C_NCON
  1126  			}
  1127  			return C_LCON
  1128  
  1129  		case obj.NAME_EXTERN,
  1130  			obj.NAME_GOTREF,
  1131  			obj.NAME_STATIC:
  1132  			s := a.Sym
  1133  			if s == nil {
  1134  				break
  1135  			}
  1136  			ctxt.Instoffset = 0 // s.b. unused but just in case
  1137  			return C_LCONADDR
  1138  
  1139  		case obj.NAME_AUTO:
  1140  			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
  1141  			return aconsize(ctxt)
  1142  
  1143  		case obj.NAME_PARAM:
  1144  			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
  1145  			return aconsize(ctxt)
  1146  		}
  1147  
  1148  		return C_GOK
  1149  
  1150  	case obj.TYPE_BRANCH:
  1151  		return C_SBRA
  1152  	}
  1153  
  1154  	return C_GOK
  1155  }
  1156  
  1157  func aconsize(ctxt *obj.Link) int {
  1158  	t := int(immrot(uint32(ctxt.Instoffset)))
  1159  	if t != 0 {
  1160  		return C_RACON
  1161  	}
  1162  	return C_LACON
  1163  }
  1164  
  1165  func prasm(p *obj.Prog) {
  1166  	fmt.Printf("%v\n", p)
  1167  }
  1168  
  1169  func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
  1170  	a1 := int(p.Optab)
  1171  	if a1 != 0 {
  1172  		return &optab[a1-1]
  1173  	}
  1174  	a1 = int(p.From.Class)
  1175  	if a1 == 0 {
  1176  		a1 = aclass(ctxt, &p.From) + 1
  1177  		p.From.Class = int8(a1)
  1178  	}
  1179  
  1180  	a1--
  1181  	a3 := int(p.To.Class)
  1182  	if a3 == 0 {
  1183  		a3 = aclass(ctxt, &p.To) + 1
  1184  		p.To.Class = int8(a3)
  1185  	}
  1186  
  1187  	a3--
  1188  	a2 := C_NONE
  1189  	if p.Reg != 0 {
  1190  		a2 = C_REG
  1191  	}
  1192  
  1193  	if false { /*debug['O']*/
  1194  		fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3))
  1195  		fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
  1196  	}
  1197  
  1198  	ops := oprange[p.As&obj.AMask]
  1199  	c1 := &xcmp[a1]
  1200  	c3 := &xcmp[a3]
  1201  	for i := range ops {
  1202  		op := &ops[i]
  1203  		if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] {
  1204  			p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
  1205  			return op
  1206  		}
  1207  	}
  1208  
  1209  	ctxt.Diag("illegal combination %v; %v %v %v, %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.To.Type)
  1210  	ctxt.Diag("from %d %d to %d %d\n", p.From.Type, p.From.Name, p.To.Type, p.To.Name)
  1211  	prasm(p)
  1212  	if ops == nil {
  1213  		ops = optab
  1214  	}
  1215  	return &ops[0]
  1216  }
  1217  
  1218  func cmp(a int, b int) bool {
  1219  	if a == b {
  1220  		return true
  1221  	}
  1222  	switch a {
  1223  	case C_LCON:
  1224  		if b == C_RCON || b == C_NCON {
  1225  			return true
  1226  		}
  1227  
  1228  	case C_LACON:
  1229  		if b == C_RACON {
  1230  			return true
  1231  		}
  1232  
  1233  	case C_LFCON:
  1234  		if b == C_ZFCON || b == C_SFCON {
  1235  			return true
  1236  		}
  1237  
  1238  	case C_HFAUTO:
  1239  		return b == C_HAUTO || b == C_FAUTO
  1240  
  1241  	case C_FAUTO, C_HAUTO:
  1242  		return b == C_HFAUTO
  1243  
  1244  	case C_SAUTO:
  1245  		return cmp(C_HFAUTO, b)
  1246  
  1247  	case C_LAUTO:
  1248  		return cmp(C_SAUTO, b)
  1249  
  1250  	case C_HFOREG:
  1251  		return b == C_HOREG || b == C_FOREG
  1252  
  1253  	case C_FOREG, C_HOREG:
  1254  		return b == C_HFOREG
  1255  
  1256  	case C_SROREG:
  1257  		return cmp(C_SOREG, b) || cmp(C_ROREG, b)
  1258  
  1259  	case C_SOREG, C_ROREG:
  1260  		return b == C_SROREG || cmp(C_HFOREG, b)
  1261  
  1262  	case C_LOREG:
  1263  		return cmp(C_SROREG, b)
  1264  
  1265  	case C_LBRA:
  1266  		if b == C_SBRA {
  1267  			return true
  1268  		}
  1269  
  1270  	case C_HREG:
  1271  		return cmp(C_SP, b) || cmp(C_PC, b)
  1272  	}
  1273  
  1274  	return false
  1275  }
  1276  
  1277  type ocmp []Optab
  1278  
  1279  func (x ocmp) Len() int {
  1280  	return len(x)
  1281  }
  1282  
  1283  func (x ocmp) Swap(i, j int) {
  1284  	x[i], x[j] = x[j], x[i]
  1285  }
  1286  
  1287  func (x ocmp) Less(i, j int) bool {
  1288  	p1 := &x[i]
  1289  	p2 := &x[j]
  1290  	n := int(p1.as) - int(p2.as)
  1291  	if n != 0 {
  1292  		return n < 0
  1293  	}
  1294  	n = int(p1.a1) - int(p2.a1)
  1295  	if n != 0 {
  1296  		return n < 0
  1297  	}
  1298  	n = int(p1.a2) - int(p2.a2)
  1299  	if n != 0 {
  1300  		return n < 0
  1301  	}
  1302  	n = int(p1.a3) - int(p2.a3)
  1303  	if n != 0 {
  1304  		return n < 0
  1305  	}
  1306  	return false
  1307  }
  1308  
  1309  func opset(a, b0 obj.As) {
  1310  	oprange[a&obj.AMask] = oprange[b0]
  1311  }
  1312  
  1313  func buildop(ctxt *obj.Link) {
  1314  	var n int
  1315  
  1316  	for i := 0; i < C_GOK; i++ {
  1317  		for n = 0; n < C_GOK; n++ {
  1318  			if cmp(n, i) {
  1319  				xcmp[i][n] = true
  1320  			}
  1321  		}
  1322  	}
  1323  	for n = 0; optab[n].as != obj.AXXX; n++ {
  1324  		if optab[n].flag&LPCREL != 0 {
  1325  			if ctxt.Flag_shared {
  1326  				optab[n].size += int8(optab[n].pcrelsiz)
  1327  			} else {
  1328  				optab[n].flag &^= LPCREL
  1329  			}
  1330  		}
  1331  	}
  1332  
  1333  	sort.Sort(ocmp(optab[:n]))
  1334  	for i := 0; i < n; i++ {
  1335  		r := optab[i].as
  1336  		r0 := r & obj.AMask
  1337  		start := i
  1338  		for optab[i].as == r {
  1339  			i++
  1340  		}
  1341  		oprange[r0] = optab[start:i]
  1342  		i--
  1343  
  1344  		switch r {
  1345  		default:
  1346  			ctxt.Diag("unknown op in build: %v", r)
  1347  			log.Fatalf("bad code")
  1348  
  1349  		case AADD:
  1350  			opset(AAND, r0)
  1351  			opset(AEOR, r0)
  1352  			opset(ASUB, r0)
  1353  			opset(ARSB, r0)
  1354  			opset(AADC, r0)
  1355  			opset(ASBC, r0)
  1356  			opset(ARSC, r0)
  1357  			opset(AORR, r0)
  1358  			opset(ABIC, r0)
  1359  
  1360  		case ACMP:
  1361  			opset(ATEQ, r0)
  1362  			opset(ACMN, r0)
  1363  
  1364  		case AMVN:
  1365  			break
  1366  
  1367  		case ABEQ:
  1368  			opset(ABNE, r0)
  1369  			opset(ABCS, r0)
  1370  			opset(ABHS, r0)
  1371  			opset(ABCC, r0)
  1372  			opset(ABLO, r0)
  1373  			opset(ABMI, r0)
  1374  			opset(ABPL, r0)
  1375  			opset(ABVS, r0)
  1376  			opset(ABVC, r0)
  1377  			opset(ABHI, r0)
  1378  			opset(ABLS, r0)
  1379  			opset(ABGE, r0)
  1380  			opset(ABLT, r0)
  1381  			opset(ABGT, r0)
  1382  			opset(ABLE, r0)
  1383  
  1384  		case ASLL:
  1385  			opset(ASRL, r0)
  1386  			opset(ASRA, r0)
  1387  
  1388  		case AMUL:
  1389  			opset(AMULU, r0)
  1390  
  1391  		case ADIV:
  1392  			opset(AMOD, r0)
  1393  			opset(AMODU, r0)
  1394  			opset(ADIVU, r0)
  1395  
  1396  		case AMOVW,
  1397  			AMOVB,
  1398  			AMOVBS,
  1399  			AMOVBU,
  1400  			AMOVH,
  1401  			AMOVHS,
  1402  			AMOVHU:
  1403  			break
  1404  
  1405  		case ASWPW:
  1406  			opset(ASWPBU, r0)
  1407  
  1408  		case AB,
  1409  			ABL,
  1410  			ABX,
  1411  			ABXRET,
  1412  			obj.ADUFFZERO,
  1413  			obj.ADUFFCOPY,
  1414  			ASWI,
  1415  			AWORD,
  1416  			AMOVM,
  1417  			ARFE,
  1418  			obj.ATEXT,
  1419  			obj.AUSEFIELD,
  1420  			obj.ATYPE:
  1421  			break
  1422  
  1423  		case AADDF:
  1424  			opset(AADDD, r0)
  1425  			opset(ASUBF, r0)
  1426  			opset(ASUBD, r0)
  1427  			opset(AMULF, r0)
  1428  			opset(AMULD, r0)
  1429  			opset(ADIVF, r0)
  1430  			opset(ADIVD, r0)
  1431  			opset(ASQRTF, r0)
  1432  			opset(ASQRTD, r0)
  1433  			opset(AMOVFD, r0)
  1434  			opset(AMOVDF, r0)
  1435  			opset(AABSF, r0)
  1436  			opset(AABSD, r0)
  1437  			opset(ANEGF, r0)
  1438  			opset(ANEGD, r0)
  1439  
  1440  		case ACMPF:
  1441  			opset(ACMPD, r0)
  1442  
  1443  		case AMOVF:
  1444  			opset(AMOVD, r0)
  1445  
  1446  		case AMOVFW:
  1447  			opset(AMOVDW, r0)
  1448  
  1449  		case AMOVWF:
  1450  			opset(AMOVWD, r0)
  1451  
  1452  		case AMULL:
  1453  			opset(AMULAL, r0)
  1454  			opset(AMULLU, r0)
  1455  			opset(AMULALU, r0)
  1456  
  1457  		case AMULWT:
  1458  			opset(AMULWB, r0)
  1459  
  1460  		case AMULAWT:
  1461  			opset(AMULAWB, r0)
  1462  
  1463  		case AMULA,
  1464  			ALDREX,
  1465  			ASTREX,
  1466  			ALDREXD,
  1467  			ASTREXD,
  1468  			ATST,
  1469  			APLD,
  1470  			obj.AUNDEF,
  1471  			ACLZ,
  1472  			obj.AFUNCDATA,
  1473  			obj.APCDATA,
  1474  			obj.ANOP,
  1475  			ADATABUNDLE,
  1476  			ADATABUNDLEEND:
  1477  			break
  1478  		}
  1479  	}
  1480  }
  1481  
  1482  func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
  1483  	ctxt.Printp = p
  1484  	o1 := uint32(0)
  1485  	o2 := uint32(0)
  1486  	o3 := uint32(0)
  1487  	o4 := uint32(0)
  1488  	o5 := uint32(0)
  1489  	o6 := uint32(0)
  1490  	ctxt.Armsize += int32(o.size)
  1491  	if false { /*debug['P']*/
  1492  		fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_)
  1493  	}
  1494  	switch o.type_ {
  1495  	default:
  1496  		ctxt.Diag("unknown asm %d", o.type_)
  1497  		prasm(p)
  1498  
  1499  	case 0: /* pseudo ops */
  1500  		if false { /*debug['G']*/
  1501  			fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name)
  1502  		}
  1503  
  1504  	case 1: /* op R,[R],R */
  1505  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1506  
  1507  		rf := int(p.From.Reg)
  1508  		rt := int(p.To.Reg)
  1509  		r := int(p.Reg)
  1510  		if p.To.Type == obj.TYPE_NONE {
  1511  			rt = 0
  1512  		}
  1513  		if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN {
  1514  			r = 0
  1515  		} else if r == 0 {
  1516  			r = rt
  1517  		}
  1518  		o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
  1519  
  1520  	case 2: /* movbu $I,[R],R */
  1521  		aclass(ctxt, &p.From)
  1522  
  1523  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1524  		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
  1525  		rt := int(p.To.Reg)
  1526  		r := int(p.Reg)
  1527  		if p.To.Type == obj.TYPE_NONE {
  1528  			rt = 0
  1529  		}
  1530  		if p.As == AMOVW || p.As == AMVN {
  1531  			r = 0
  1532  		} else if r == 0 {
  1533  			r = rt
  1534  		}
  1535  		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
  1536  
  1537  	case 3: /* add R<<[IR],[R],R */
  1538  		o1 = mov(ctxt, p)
  1539  
  1540  	case 4: /* add $I,[R],R */
  1541  		aclass(ctxt, &p.From)
  1542  
  1543  		o1 = oprrr(ctxt, AADD, int(p.Scond))
  1544  		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
  1545  		r := int(p.From.Reg)
  1546  		if r == 0 {
  1547  			r = int(o.param)
  1548  		}
  1549  		o1 |= (uint32(r) & 15) << 16
  1550  		o1 |= (uint32(p.To.Reg) & 15) << 12
  1551  
  1552  	case 5: /* bra s */
  1553  		o1 = opbra(ctxt, p, p.As, int(p.Scond))
  1554  
  1555  		v := int32(-8)
  1556  		if p.To.Sym != nil {
  1557  			rel := obj.Addrel(ctxt.Cursym)
  1558  			rel.Off = int32(ctxt.Pc)
  1559  			rel.Siz = 4
  1560  			rel.Sym = p.To.Sym
  1561  			v += int32(p.To.Offset)
  1562  			rel.Add = int64(o1) | (int64(v)>>2)&0xffffff
  1563  			rel.Type = obj.R_CALLARM
  1564  			break
  1565  		}
  1566  
  1567  		if p.Pcond != nil {
  1568  			v = int32((p.Pcond.Pc - ctxt.Pc) - 8)
  1569  		}
  1570  		o1 |= (uint32(v) >> 2) & 0xffffff
  1571  
  1572  	case 6: /* b ,O(R) -> add $O,R,PC */
  1573  		aclass(ctxt, &p.To)
  1574  
  1575  		o1 = oprrr(ctxt, AADD, int(p.Scond))
  1576  		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
  1577  		o1 |= (uint32(p.To.Reg) & 15) << 16
  1578  		o1 |= (REGPC & 15) << 12
  1579  
  1580  	case 7: /* bl (R) -> blx R */
  1581  		aclass(ctxt, &p.To)
  1582  
  1583  		if ctxt.Instoffset != 0 {
  1584  			ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, ctxt.Instoffset)
  1585  		}
  1586  		o1 = oprrr(ctxt, ABL, int(p.Scond))
  1587  		o1 |= (uint32(p.To.Reg) & 15) << 0
  1588  		rel := obj.Addrel(ctxt.Cursym)
  1589  		rel.Off = int32(ctxt.Pc)
  1590  		rel.Siz = 0
  1591  		rel.Type = obj.R_CALLIND
  1592  
  1593  	case 8: /* sll $c,[R],R -> mov (R<<$c),R */
  1594  		aclass(ctxt, &p.From)
  1595  
  1596  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1597  		r := int(p.Reg)
  1598  		if r == 0 {
  1599  			r = int(p.To.Reg)
  1600  		}
  1601  		o1 |= (uint32(r) & 15) << 0
  1602  		o1 |= uint32((ctxt.Instoffset & 31) << 7)
  1603  		o1 |= (uint32(p.To.Reg) & 15) << 12
  1604  
  1605  	case 9: /* sll R,[R],R -> mov (R<<R),R */
  1606  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1607  
  1608  		r := int(p.Reg)
  1609  		if r == 0 {
  1610  			r = int(p.To.Reg)
  1611  		}
  1612  		o1 |= (uint32(r) & 15) << 0
  1613  		o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4
  1614  		o1 |= (uint32(p.To.Reg) & 15) << 12
  1615  
  1616  	case 10: /* swi [$con] */
  1617  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1618  
  1619  		if p.To.Type != obj.TYPE_NONE {
  1620  			aclass(ctxt, &p.To)
  1621  			o1 |= uint32(ctxt.Instoffset & 0xffffff)
  1622  		}
  1623  
  1624  	case 11: /* word */
  1625  		aclass(ctxt, &p.To)
  1626  
  1627  		o1 = uint32(ctxt.Instoffset)
  1628  		if p.To.Sym != nil {
  1629  			// This case happens with words generated
  1630  			// in the PC stream as part of the literal pool.
  1631  			rel := obj.Addrel(ctxt.Cursym)
  1632  
  1633  			rel.Off = int32(ctxt.Pc)
  1634  			rel.Siz = 4
  1635  			rel.Sym = p.To.Sym
  1636  			rel.Add = p.To.Offset
  1637  
  1638  			if ctxt.Flag_shared {
  1639  				if p.To.Name == obj.NAME_GOTREF {
  1640  					rel.Type = obj.R_GOTPCREL
  1641  				} else {
  1642  					rel.Type = obj.R_PCREL
  1643  				}
  1644  				rel.Add += ctxt.Pc - p.Rel.Pc - 8
  1645  			} else {
  1646  				rel.Type = obj.R_ADDR
  1647  			}
  1648  			o1 = 0
  1649  		}
  1650  
  1651  	case 12: /* movw $lcon, reg */
  1652  		o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
  1653  
  1654  		if o.flag&LPCREL != 0 {
  1655  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12
  1656  		}
  1657  
  1658  	case 13: /* op $lcon, [R], R */
  1659  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  1660  
  1661  		if o1 == 0 {
  1662  			break
  1663  		}
  1664  		o2 = oprrr(ctxt, p.As, int(p.Scond))
  1665  		o2 |= REGTMP & 15
  1666  		r := int(p.Reg)
  1667  		if p.As == AMOVW || p.As == AMVN {
  1668  			r = 0
  1669  		} else if r == 0 {
  1670  			r = int(p.To.Reg)
  1671  		}
  1672  		o2 |= (uint32(r) & 15) << 16
  1673  		if p.To.Type != obj.TYPE_NONE {
  1674  			o2 |= (uint32(p.To.Reg) & 15) << 12
  1675  		}
  1676  
  1677  	case 14: /* movb/movbu/movh/movhu R,R */
  1678  		o1 = oprrr(ctxt, ASLL, int(p.Scond))
  1679  
  1680  		if p.As == AMOVBU || p.As == AMOVHU {
  1681  			o2 = oprrr(ctxt, ASRL, int(p.Scond))
  1682  		} else {
  1683  			o2 = oprrr(ctxt, ASRA, int(p.Scond))
  1684  		}
  1685  
  1686  		r := int(p.To.Reg)
  1687  		o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12
  1688  		o2 |= uint32(r)&15 | (uint32(r)&15)<<12
  1689  		if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
  1690  			o1 |= 24 << 7
  1691  			o2 |= 24 << 7
  1692  		} else {
  1693  			o1 |= 16 << 7
  1694  			o2 |= 16 << 7
  1695  		}
  1696  
  1697  	case 15: /* mul r,[r,]r */
  1698  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1699  
  1700  		rf := int(p.From.Reg)
  1701  		rt := int(p.To.Reg)
  1702  		r := int(p.Reg)
  1703  		if r == 0 {
  1704  			r = rt
  1705  		}
  1706  		if rt == r {
  1707  			r = rf
  1708  			rf = rt
  1709  		}
  1710  
  1711  		if false {
  1712  			if rt == r || rf == REGPC&15 || r == REGPC&15 || rt == REGPC&15 {
  1713  				ctxt.Diag("bad registers in MUL")
  1714  				prasm(p)
  1715  			}
  1716  		}
  1717  
  1718  		o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
  1719  
  1720  	case 16: /* div r,[r,]r */
  1721  		o1 = 0xf << 28
  1722  
  1723  		o2 = 0
  1724  
  1725  	case 17:
  1726  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1727  		rf := int(p.From.Reg)
  1728  		rt := int(p.To.Reg)
  1729  		rt2 := int(p.To.Offset)
  1730  		r := int(p.Reg)
  1731  		o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12
  1732  
  1733  	case 20: /* mov/movb/movbu R,O(R) */
  1734  		aclass(ctxt, &p.To)
  1735  
  1736  		r := int(p.To.Reg)
  1737  		if r == 0 {
  1738  			r = int(o.param)
  1739  		}
  1740  		o1 = osr(ctxt, p.As, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
  1741  
  1742  	case 21: /* mov/movbu O(R),R -> lr */
  1743  		aclass(ctxt, &p.From)
  1744  
  1745  		r := int(p.From.Reg)
  1746  		if r == 0 {
  1747  			r = int(o.param)
  1748  		}
  1749  		o1 = olr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
  1750  		if p.As != AMOVW {
  1751  			o1 |= 1 << 22
  1752  		}
  1753  
  1754  	case 30: /* mov/movb/movbu R,L(R) */
  1755  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  1756  
  1757  		if o1 == 0 {
  1758  			break
  1759  		}
  1760  		r := int(p.To.Reg)
  1761  		if r == 0 {
  1762  			r = int(o.param)
  1763  		}
  1764  		o2 = osrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
  1765  		if p.As != AMOVW {
  1766  			o2 |= 1 << 22
  1767  		}
  1768  
  1769  	case 31: /* mov/movbu L(R),R -> lr[b] */
  1770  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  1771  
  1772  		if o1 == 0 {
  1773  			break
  1774  		}
  1775  		r := int(p.From.Reg)
  1776  		if r == 0 {
  1777  			r = int(o.param)
  1778  		}
  1779  		o2 = olrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
  1780  		if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
  1781  			o2 |= 1 << 22
  1782  		}
  1783  
  1784  	case 34: /* mov $lacon,R */
  1785  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  1786  
  1787  		if o1 == 0 {
  1788  			break
  1789  		}
  1790  
  1791  		o2 = oprrr(ctxt, AADD, int(p.Scond))
  1792  		o2 |= REGTMP & 15
  1793  		r := int(p.From.Reg)
  1794  		if r == 0 {
  1795  			r = int(o.param)
  1796  		}
  1797  		o2 |= (uint32(r) & 15) << 16
  1798  		if p.To.Type != obj.TYPE_NONE {
  1799  			o2 |= (uint32(p.To.Reg) & 15) << 12
  1800  		}
  1801  
  1802  	case 35: /* mov PSR,R */
  1803  		o1 = 2<<23 | 0xf<<16 | 0<<0
  1804  
  1805  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  1806  		o1 |= (uint32(p.From.Reg) & 1) << 22
  1807  		o1 |= (uint32(p.To.Reg) & 15) << 12
  1808  
  1809  	case 36: /* mov R,PSR */
  1810  		o1 = 2<<23 | 0x29f<<12 | 0<<4
  1811  
  1812  		if p.Scond&C_FBIT != 0 {
  1813  			o1 ^= 0x010 << 12
  1814  		}
  1815  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  1816  		o1 |= (uint32(p.To.Reg) & 1) << 22
  1817  		o1 |= (uint32(p.From.Reg) & 15) << 0
  1818  
  1819  	case 37: /* mov $con,PSR */
  1820  		aclass(ctxt, &p.From)
  1821  
  1822  		o1 = 2<<23 | 0x29f<<12 | 0<<4
  1823  		if p.Scond&C_FBIT != 0 {
  1824  			o1 ^= 0x010 << 12
  1825  		}
  1826  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  1827  		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
  1828  		o1 |= (uint32(p.To.Reg) & 1) << 22
  1829  		o1 |= (uint32(p.From.Reg) & 15) << 0
  1830  
  1831  	case 38, 39:
  1832  		switch o.type_ {
  1833  		case 38: /* movm $con,oreg -> stm */
  1834  			o1 = 0x4 << 25
  1835  
  1836  			o1 |= uint32(p.From.Offset & 0xffff)
  1837  			o1 |= (uint32(p.To.Reg) & 15) << 16
  1838  			aclass(ctxt, &p.To)
  1839  
  1840  		case 39: /* movm oreg,$con -> ldm */
  1841  			o1 = 0x4<<25 | 1<<20
  1842  
  1843  			o1 |= uint32(p.To.Offset & 0xffff)
  1844  			o1 |= (uint32(p.From.Reg) & 15) << 16
  1845  			aclass(ctxt, &p.From)
  1846  		}
  1847  
  1848  		if ctxt.Instoffset != 0 {
  1849  			ctxt.Diag("offset must be zero in MOVM; %v", p)
  1850  		}
  1851  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  1852  		if p.Scond&C_PBIT != 0 {
  1853  			o1 |= 1 << 24
  1854  		}
  1855  		if p.Scond&C_UBIT != 0 {
  1856  			o1 |= 1 << 23
  1857  		}
  1858  		if p.Scond&C_SBIT != 0 {
  1859  			o1 |= 1 << 22
  1860  		}
  1861  		if p.Scond&C_WBIT != 0 {
  1862  			o1 |= 1 << 21
  1863  		}
  1864  
  1865  	case 40: /* swp oreg,reg,reg */
  1866  		aclass(ctxt, &p.From)
  1867  
  1868  		if ctxt.Instoffset != 0 {
  1869  			ctxt.Diag("offset must be zero in SWP")
  1870  		}
  1871  		o1 = 0x2<<23 | 0x9<<4
  1872  		if p.As != ASWPW {
  1873  			o1 |= 1 << 22
  1874  		}
  1875  		o1 |= (uint32(p.From.Reg) & 15) << 16
  1876  		o1 |= (uint32(p.Reg) & 15) << 0
  1877  		o1 |= (uint32(p.To.Reg) & 15) << 12
  1878  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  1879  
  1880  	case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
  1881  		o1 = 0xe8fd8000
  1882  
  1883  	case 50: /* floating point store */
  1884  		v := regoff(ctxt, &p.To)
  1885  
  1886  		r := int(p.To.Reg)
  1887  		if r == 0 {
  1888  			r = int(o.param)
  1889  		}
  1890  		o1 = ofsr(ctxt, p.As, int(p.From.Reg), v, r, int(p.Scond), p)
  1891  
  1892  	case 51: /* floating point load */
  1893  		v := regoff(ctxt, &p.From)
  1894  
  1895  		r := int(p.From.Reg)
  1896  		if r == 0 {
  1897  			r = int(o.param)
  1898  		}
  1899  		o1 = ofsr(ctxt, p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20
  1900  
  1901  	case 52: /* floating point store, int32 offset UGLY */
  1902  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  1903  
  1904  		if o1 == 0 {
  1905  			break
  1906  		}
  1907  		r := int(p.To.Reg)
  1908  		if r == 0 {
  1909  			r = int(o.param)
  1910  		}
  1911  		o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
  1912  		o3 = ofsr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
  1913  
  1914  	case 53: /* floating point load, int32 offset UGLY */
  1915  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  1916  
  1917  		if o1 == 0 {
  1918  			break
  1919  		}
  1920  		r := int(p.From.Reg)
  1921  		if r == 0 {
  1922  			r = int(o.param)
  1923  		}
  1924  		o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
  1925  		o3 = ofsr(ctxt, p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
  1926  
  1927  	case 54: /* floating point arith */
  1928  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1929  
  1930  		rf := int(p.From.Reg)
  1931  		rt := int(p.To.Reg)
  1932  		r := int(p.Reg)
  1933  		if r == 0 {
  1934  			r = rt
  1935  			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 {
  1936  				r = 0
  1937  			}
  1938  		}
  1939  
  1940  		o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
  1941  
  1942  	case 56: /* move to FP[CS]R */
  1943  		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
  1944  
  1945  		o1 |= ((uint32(p.To.Reg)&1)+1)<<21 | (uint32(p.From.Reg)&15)<<12
  1946  
  1947  	case 57: /* move from FP[CS]R */
  1948  		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
  1949  
  1950  		o1 |= ((uint32(p.From.Reg)&1)+1)<<21 | (uint32(p.To.Reg)&15)<<12 | 1<<20
  1951  
  1952  	case 58: /* movbu R,R */
  1953  		o1 = oprrr(ctxt, AAND, int(p.Scond))
  1954  
  1955  		o1 |= uint32(immrot(0xff))
  1956  		rt := int(p.To.Reg)
  1957  		r := int(p.From.Reg)
  1958  		if p.To.Type == obj.TYPE_NONE {
  1959  			rt = 0
  1960  		}
  1961  		if r == 0 {
  1962  			r = rt
  1963  		}
  1964  		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
  1965  
  1966  	case 59: /* movw/bu R<<I(R),R -> ldr indexed */
  1967  		if p.From.Reg == 0 {
  1968  			if p.As != AMOVW {
  1969  				ctxt.Diag("byte MOV from shifter operand")
  1970  			}
  1971  			o1 = mov(ctxt, p)
  1972  			break
  1973  		}
  1974  
  1975  		if p.From.Offset&(1<<4) != 0 {
  1976  			ctxt.Diag("bad shift in LDR")
  1977  		}
  1978  		o1 = olrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
  1979  		if p.As == AMOVBU {
  1980  			o1 |= 1 << 22
  1981  		}
  1982  
  1983  	case 60: /* movb R(R),R -> ldrsb indexed */
  1984  		if p.From.Reg == 0 {
  1985  			ctxt.Diag("byte MOV from shifter operand")
  1986  			o1 = mov(ctxt, p)
  1987  			break
  1988  		}
  1989  
  1990  		if p.From.Offset&(^0xf) != 0 {
  1991  			ctxt.Diag("bad shift in LDRSB")
  1992  		}
  1993  		o1 = olhrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
  1994  		o1 ^= 1<<5 | 1<<6
  1995  
  1996  	case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
  1997  		if p.To.Reg == 0 {
  1998  			ctxt.Diag("MOV to shifter operand")
  1999  		}
  2000  		o1 = osrr(ctxt, int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond))
  2001  		if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
  2002  			o1 |= 1 << 22
  2003  		}
  2004  
  2005  		/* reloc ops */
  2006  	case 64: /* mov/movb/movbu R,addr */
  2007  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  2008  
  2009  		if o1 == 0 {
  2010  			break
  2011  		}
  2012  		o2 = osr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond))
  2013  		if o.flag&LPCREL != 0 {
  2014  			o3 = o2
  2015  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2016  		}
  2017  
  2018  	case 65: /* mov/movbu addr,R */
  2019  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  2020  
  2021  		if o1 == 0 {
  2022  			break
  2023  		}
  2024  		o2 = olr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
  2025  		if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
  2026  			o2 |= 1 << 22
  2027  		}
  2028  		if o.flag&LPCREL != 0 {
  2029  			o3 = o2
  2030  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2031  		}
  2032  
  2033  	case 101: /* movw tlsvar,R, local exec*/
  2034  		if p.Scond&C_SCOND != C_SCOND_NONE {
  2035  			ctxt.Diag("conditional tls")
  2036  		}
  2037  		o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
  2038  
  2039  	case 102: /* movw tlsvar,R, initial exec*/
  2040  		if p.Scond&C_SCOND != C_SCOND_NONE {
  2041  			ctxt.Diag("conditional tls")
  2042  		}
  2043  		o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
  2044  		o2 = olrr(ctxt, int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond))
  2045  
  2046  	case 103: /* word tlsvar, local exec */
  2047  		if p.To.Sym == nil {
  2048  			ctxt.Diag("nil sym in tls %v", p)
  2049  		}
  2050  		if p.To.Offset != 0 {
  2051  			ctxt.Diag("offset against tls var in %v", p)
  2052  		}
  2053  		// This case happens with words generated in the PC stream as part of
  2054  		// the literal pool.
  2055  		rel := obj.Addrel(ctxt.Cursym)
  2056  
  2057  		rel.Off = int32(ctxt.Pc)
  2058  		rel.Siz = 4
  2059  		rel.Sym = p.To.Sym
  2060  		rel.Type = obj.R_TLS_LE
  2061  		o1 = 0
  2062  
  2063  	case 104: /* word tlsvar, initial exec */
  2064  		if p.To.Sym == nil {
  2065  			ctxt.Diag("nil sym in tls %v", p)
  2066  		}
  2067  		if p.To.Offset != 0 {
  2068  			ctxt.Diag("offset against tls var in %v", p)
  2069  		}
  2070  		rel := obj.Addrel(ctxt.Cursym)
  2071  		rel.Off = int32(ctxt.Pc)
  2072  		rel.Siz = 4
  2073  		rel.Sym = p.To.Sym
  2074  		rel.Type = obj.R_TLS_IE
  2075  		rel.Add = ctxt.Pc - p.Rel.Pc - 8 - int64(rel.Siz)
  2076  
  2077  	case 68: /* floating point store -> ADDR */
  2078  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  2079  
  2080  		if o1 == 0 {
  2081  			break
  2082  		}
  2083  		o2 = ofsr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
  2084  		if o.flag&LPCREL != 0 {
  2085  			o3 = o2
  2086  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2087  		}
  2088  
  2089  	case 69: /* floating point load <- ADDR */
  2090  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  2091  
  2092  		if o1 == 0 {
  2093  			break
  2094  		}
  2095  		o2 = ofsr(ctxt, p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
  2096  		if o.flag&LPCREL != 0 {
  2097  			o3 = o2
  2098  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2099  		}
  2100  
  2101  		/* ArmV4 ops: */
  2102  	case 70: /* movh/movhu R,O(R) -> strh */
  2103  		aclass(ctxt, &p.To)
  2104  
  2105  		r := int(p.To.Reg)
  2106  		if r == 0 {
  2107  			r = int(o.param)
  2108  		}
  2109  		o1 = oshr(ctxt, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
  2110  
  2111  	case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
  2112  		aclass(ctxt, &p.From)
  2113  
  2114  		r := int(p.From.Reg)
  2115  		if r == 0 {
  2116  			r = int(o.param)
  2117  		}
  2118  		o1 = olhr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
  2119  		if p.As == AMOVB || p.As == AMOVBS {
  2120  			o1 ^= 1<<5 | 1<<6
  2121  		} else if p.As == AMOVH || p.As == AMOVHS {
  2122  			o1 ^= (1 << 6)
  2123  		}
  2124  
  2125  	case 72: /* movh/movhu R,L(R) -> strh */
  2126  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  2127  
  2128  		if o1 == 0 {
  2129  			break
  2130  		}
  2131  		r := int(p.To.Reg)
  2132  		if r == 0 {
  2133  			r = int(o.param)
  2134  		}
  2135  		o2 = oshrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
  2136  
  2137  	case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
  2138  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  2139  
  2140  		if o1 == 0 {
  2141  			break
  2142  		}
  2143  		r := int(p.From.Reg)
  2144  		if r == 0 {
  2145  			r = int(o.param)
  2146  		}
  2147  		o2 = olhrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
  2148  		if p.As == AMOVB || p.As == AMOVBS {
  2149  			o2 ^= 1<<5 | 1<<6
  2150  		} else if p.As == AMOVH || p.As == AMOVHS {
  2151  			o2 ^= (1 << 6)
  2152  		}
  2153  
  2154  	case 74: /* bx $I */
  2155  		ctxt.Diag("ABX $I")
  2156  
  2157  	case 75: /* bx O(R) */
  2158  		aclass(ctxt, &p.To)
  2159  
  2160  		if ctxt.Instoffset != 0 {
  2161  			ctxt.Diag("non-zero offset in ABX")
  2162  		}
  2163  
  2164  		/*
  2165  			o1 = 	oprrr(ctxt, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12);	// mov PC, LR
  2166  			o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0);		// BX R
  2167  		*/
  2168  		// p->to.reg may be REGLINK
  2169  		o1 = oprrr(ctxt, AADD, int(p.Scond))
  2170  
  2171  		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
  2172  		o1 |= (uint32(p.To.Reg) & 15) << 16
  2173  		o1 |= (REGTMP & 15) << 12
  2174  		o2 = oprrr(ctxt, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR
  2175  		o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15             // BX Rtmp
  2176  
  2177  	case 76: /* bx O(R) when returning from fn*/
  2178  		ctxt.Diag("ABXRET")
  2179  
  2180  	case 77: /* ldrex oreg,reg */
  2181  		aclass(ctxt, &p.From)
  2182  
  2183  		if ctxt.Instoffset != 0 {
  2184  			ctxt.Diag("offset must be zero in LDREX")
  2185  		}
  2186  		o1 = 0x19<<20 | 0xf9f
  2187  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2188  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2189  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2190  
  2191  	case 78: /* strex reg,oreg,reg */
  2192  		aclass(ctxt, &p.From)
  2193  
  2194  		if ctxt.Instoffset != 0 {
  2195  			ctxt.Diag("offset must be zero in STREX")
  2196  		}
  2197  		o1 = 0x18<<20 | 0xf90
  2198  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2199  		o1 |= (uint32(p.Reg) & 15) << 0
  2200  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2201  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2202  
  2203  	case 80: /* fmov zfcon,freg */
  2204  		if p.As == AMOVD {
  2205  			o1 = 0xeeb00b00 // VMOV imm 64
  2206  			o2 = oprrr(ctxt, ASUBD, int(p.Scond))
  2207  		} else {
  2208  			o1 = 0x0eb00a00 // VMOV imm 32
  2209  			o2 = oprrr(ctxt, ASUBF, int(p.Scond))
  2210  		}
  2211  
  2212  		v := int32(0x70) // 1.0
  2213  		r := (int(p.To.Reg) & 15) << 0
  2214  
  2215  		// movf $1.0, r
  2216  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2217  
  2218  		o1 |= (uint32(r) & 15) << 12
  2219  		o1 |= (uint32(v) & 0xf) << 0
  2220  		o1 |= (uint32(v) & 0xf0) << 12
  2221  
  2222  		// subf r,r,r
  2223  		o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12
  2224  
  2225  	case 81: /* fmov sfcon,freg */
  2226  		o1 = 0x0eb00a00 // VMOV imm 32
  2227  		if p.As == AMOVD {
  2228  			o1 = 0xeeb00b00 // VMOV imm 64
  2229  		}
  2230  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2231  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2232  		v := int32(chipfloat5(ctxt, p.From.Val.(float64)))
  2233  		o1 |= (uint32(v) & 0xf) << 0
  2234  		o1 |= (uint32(v) & 0xf0) << 12
  2235  
  2236  	case 82: /* fcmp freg,freg, */
  2237  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2238  
  2239  		o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0
  2240  		o2 = 0x0ef1fa10 // VMRS R15
  2241  		o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2242  
  2243  	case 83: /* fcmp freg,, */
  2244  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2245  
  2246  		o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16
  2247  		o2 = 0x0ef1fa10 // VMRS R15
  2248  		o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2249  
  2250  	case 84: /* movfw freg,freg - truncate float-to-fix */
  2251  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2252  
  2253  		o1 |= (uint32(p.From.Reg) & 15) << 0
  2254  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2255  
  2256  	case 85: /* movwf freg,freg - fix-to-float */
  2257  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2258  
  2259  		o1 |= (uint32(p.From.Reg) & 15) << 0
  2260  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2261  
  2262  		// macro for movfw freg,FTMP; movw FTMP,reg
  2263  	case 86: /* movfw freg,reg - truncate float-to-fix */
  2264  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2265  
  2266  		o1 |= (uint32(p.From.Reg) & 15) << 0
  2267  		o1 |= (FREGTMP & 15) << 12
  2268  		o2 = oprrr(ctxt, -AMOVFW, int(p.Scond))
  2269  		o2 |= (FREGTMP & 15) << 16
  2270  		o2 |= (uint32(p.To.Reg) & 15) << 12
  2271  
  2272  		// macro for movw reg,FTMP; movwf FTMP,freg
  2273  	case 87: /* movwf reg,freg - fix-to-float */
  2274  		o1 = oprrr(ctxt, -AMOVWF, int(p.Scond))
  2275  
  2276  		o1 |= (uint32(p.From.Reg) & 15) << 12
  2277  		o1 |= (FREGTMP & 15) << 16
  2278  		o2 = oprrr(ctxt, p.As, int(p.Scond))
  2279  		o2 |= (FREGTMP & 15) << 0
  2280  		o2 |= (uint32(p.To.Reg) & 15) << 12
  2281  
  2282  	case 88: /* movw reg,freg  */
  2283  		o1 = oprrr(ctxt, -AMOVWF, int(p.Scond))
  2284  
  2285  		o1 |= (uint32(p.From.Reg) & 15) << 12
  2286  		o1 |= (uint32(p.To.Reg) & 15) << 16
  2287  
  2288  	case 89: /* movw freg,reg  */
  2289  		o1 = oprrr(ctxt, -AMOVFW, int(p.Scond))
  2290  
  2291  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2292  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2293  
  2294  	case 90: /* tst reg  */
  2295  		o1 = oprrr(ctxt, -ACMP, int(p.Scond))
  2296  
  2297  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2298  
  2299  	case 91: /* ldrexd oreg,reg */
  2300  		aclass(ctxt, &p.From)
  2301  
  2302  		if ctxt.Instoffset != 0 {
  2303  			ctxt.Diag("offset must be zero in LDREX")
  2304  		}
  2305  		o1 = 0x1b<<20 | 0xf9f
  2306  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2307  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2308  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2309  
  2310  	case 92: /* strexd reg,oreg,reg */
  2311  		aclass(ctxt, &p.From)
  2312  
  2313  		if ctxt.Instoffset != 0 {
  2314  			ctxt.Diag("offset must be zero in STREX")
  2315  		}
  2316  		o1 = 0x1a<<20 | 0xf90
  2317  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2318  		o1 |= (uint32(p.Reg) & 15) << 0
  2319  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2320  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2321  
  2322  	case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
  2323  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  2324  
  2325  		if o1 == 0 {
  2326  			break
  2327  		}
  2328  		o2 = olhr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
  2329  		if p.As == AMOVB || p.As == AMOVBS {
  2330  			o2 ^= 1<<5 | 1<<6
  2331  		} else if p.As == AMOVH || p.As == AMOVHS {
  2332  			o2 ^= (1 << 6)
  2333  		}
  2334  		if o.flag&LPCREL != 0 {
  2335  			o3 = o2
  2336  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2337  		}
  2338  
  2339  	case 94: /* movh/movhu R,addr -> strh */
  2340  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  2341  
  2342  		if o1 == 0 {
  2343  			break
  2344  		}
  2345  		o2 = oshr(ctxt, int(p.From.Reg), 0, REGTMP, int(p.Scond))
  2346  		if o.flag&LPCREL != 0 {
  2347  			o3 = o2
  2348  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2349  		}
  2350  
  2351  	case 95: /* PLD off(reg) */
  2352  		o1 = 0xf5d0f000
  2353  
  2354  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2355  		if p.From.Offset < 0 {
  2356  			o1 &^= (1 << 23)
  2357  			o1 |= uint32((-p.From.Offset) & 0xfff)
  2358  		} else {
  2359  			o1 |= uint32(p.From.Offset & 0xfff)
  2360  		}
  2361  
  2362  		// This is supposed to be something that stops execution.
  2363  	// It's not supposed to be reached, ever, but if it is, we'd
  2364  	// like to be able to tell how we got there. Assemble as
  2365  	// 0xf7fabcfd which is guaranteed to raise undefined instruction
  2366  	// exception.
  2367  	case 96: /* UNDEF */
  2368  		o1 = 0xf7fabcfd
  2369  
  2370  	case 97: /* CLZ Rm, Rd */
  2371  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2372  
  2373  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2374  		o1 |= (uint32(p.From.Reg) & 15) << 0
  2375  
  2376  	case 98: /* MULW{T,B} Rs, Rm, Rd */
  2377  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2378  
  2379  		o1 |= (uint32(p.To.Reg) & 15) << 16
  2380  		o1 |= (uint32(p.From.Reg) & 15) << 8
  2381  		o1 |= (uint32(p.Reg) & 15) << 0
  2382  
  2383  	case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
  2384  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2385  
  2386  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2387  		o1 |= (uint32(p.From.Reg) & 15) << 8
  2388  		o1 |= (uint32(p.Reg) & 15) << 0
  2389  		o1 |= uint32((p.To.Offset & 15) << 16)
  2390  
  2391  		// DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
  2392  	// DATABUNDLEEND: zero width alignment marker
  2393  	case 100:
  2394  		if p.As == ADATABUNDLE {
  2395  			o1 = 0xe125be70
  2396  		}
  2397  	}
  2398  
  2399  	out[0] = o1
  2400  	out[1] = o2
  2401  	out[2] = o3
  2402  	out[3] = o4
  2403  	out[4] = o5
  2404  	out[5] = o6
  2405  	return
  2406  }
  2407  
  2408  func mov(ctxt *obj.Link, p *obj.Prog) uint32 {
  2409  	aclass(ctxt, &p.From)
  2410  	o1 := oprrr(ctxt, p.As, int(p.Scond))
  2411  	o1 |= uint32(p.From.Offset)
  2412  	rt := int(p.To.Reg)
  2413  	if p.To.Type == obj.TYPE_NONE {
  2414  		rt = 0
  2415  	}
  2416  	r := int(p.Reg)
  2417  	if p.As == AMOVW || p.As == AMVN {
  2418  		r = 0
  2419  	} else if r == 0 {
  2420  		r = rt
  2421  	}
  2422  	o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
  2423  	return o1
  2424  }
  2425  
  2426  func oprrr(ctxt *obj.Link, a obj.As, sc int) uint32 {
  2427  	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
  2428  	if sc&C_SBIT != 0 {
  2429  		o |= 1 << 20
  2430  	}
  2431  	if sc&(C_PBIT|C_WBIT) != 0 {
  2432  		ctxt.Diag(".nil/.W on dp instruction")
  2433  	}
  2434  	switch a {
  2435  	case AMULU, AMUL:
  2436  		return o | 0x0<<21 | 0x9<<4
  2437  	case AMULA:
  2438  		return o | 0x1<<21 | 0x9<<4
  2439  	case AMULLU:
  2440  		return o | 0x4<<21 | 0x9<<4
  2441  	case AMULL:
  2442  		return o | 0x6<<21 | 0x9<<4
  2443  	case AMULALU:
  2444  		return o | 0x5<<21 | 0x9<<4
  2445  	case AMULAL:
  2446  		return o | 0x7<<21 | 0x9<<4
  2447  	case AAND:
  2448  		return o | 0x0<<21
  2449  	case AEOR:
  2450  		return o | 0x1<<21
  2451  	case ASUB:
  2452  		return o | 0x2<<21
  2453  	case ARSB:
  2454  		return o | 0x3<<21
  2455  	case AADD:
  2456  		return o | 0x4<<21
  2457  	case AADC:
  2458  		return o | 0x5<<21
  2459  	case ASBC:
  2460  		return o | 0x6<<21
  2461  	case ARSC:
  2462  		return o | 0x7<<21
  2463  	case ATST:
  2464  		return o | 0x8<<21 | 1<<20
  2465  	case ATEQ:
  2466  		return o | 0x9<<21 | 1<<20
  2467  	case ACMP:
  2468  		return o | 0xa<<21 | 1<<20
  2469  	case ACMN:
  2470  		return o | 0xb<<21 | 1<<20
  2471  	case AORR:
  2472  		return o | 0xc<<21
  2473  
  2474  	case AMOVB, AMOVH, AMOVW:
  2475  		return o | 0xd<<21
  2476  	case ABIC:
  2477  		return o | 0xe<<21
  2478  	case AMVN:
  2479  		return o | 0xf<<21
  2480  	case ASLL:
  2481  		return o | 0xd<<21 | 0<<5
  2482  	case ASRL:
  2483  		return o | 0xd<<21 | 1<<5
  2484  	case ASRA:
  2485  		return o | 0xd<<21 | 2<<5
  2486  	case ASWI:
  2487  		return o | 0xf<<24
  2488  
  2489  	case AADDD:
  2490  		return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4
  2491  	case AADDF:
  2492  		return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4
  2493  	case ASUBD:
  2494  		return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4
  2495  	case ASUBF:
  2496  		return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4
  2497  	case AMULD:
  2498  		return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4
  2499  	case AMULF:
  2500  		return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4
  2501  	case ADIVD:
  2502  		return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4
  2503  	case ADIVF:
  2504  		return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4
  2505  	case ASQRTD:
  2506  		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4
  2507  	case ASQRTF:
  2508  		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4
  2509  	case AABSD:
  2510  		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4
  2511  	case AABSF:
  2512  		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4
  2513  	case ANEGD:
  2514  		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0x4<<4
  2515  	case ANEGF:
  2516  		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0x4<<4
  2517  	case ACMPD:
  2518  		return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4
  2519  	case ACMPF:
  2520  		return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4
  2521  
  2522  	case AMOVF:
  2523  		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4
  2524  	case AMOVD:
  2525  		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4
  2526  
  2527  	case AMOVDF:
  2528  		return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof
  2529  	case AMOVFD:
  2530  		return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof
  2531  
  2532  	case AMOVWF:
  2533  		if sc&C_UBIT == 0 {
  2534  			o |= 1 << 7 /* signed */
  2535  		}
  2536  		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double
  2537  
  2538  	case AMOVWD:
  2539  		if sc&C_UBIT == 0 {
  2540  			o |= 1 << 7 /* signed */
  2541  		}
  2542  		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double
  2543  
  2544  	case AMOVFW:
  2545  		if sc&C_UBIT == 0 {
  2546  			o |= 1 << 16 /* signed */
  2547  		}
  2548  		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc
  2549  
  2550  	case AMOVDW:
  2551  		if sc&C_UBIT == 0 {
  2552  			o |= 1 << 16 /* signed */
  2553  		}
  2554  		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc
  2555  
  2556  	case -AMOVWF: // copy WtoF
  2557  		return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4
  2558  
  2559  	case -AMOVFW: // copy FtoW
  2560  		return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4
  2561  
  2562  	case -ACMP: // cmp imm
  2563  		return o | 0x3<<24 | 0x5<<20
  2564  
  2565  		// CLZ doesn't support .nil
  2566  	case ACLZ:
  2567  		return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4
  2568  
  2569  	case AMULWT:
  2570  		return o&(0xf<<28) | 0x12<<20 | 0xe<<4
  2571  
  2572  	case AMULWB:
  2573  		return o&(0xf<<28) | 0x12<<20 | 0xa<<4
  2574  
  2575  	case AMULAWT:
  2576  		return o&(0xf<<28) | 0x12<<20 | 0xc<<4
  2577  
  2578  	case AMULAWB:
  2579  		return o&(0xf<<28) | 0x12<<20 | 0x8<<4
  2580  
  2581  	case ABL: // BLX REG
  2582  		return o&(0xf<<28) | 0x12fff3<<4
  2583  	}
  2584  
  2585  	ctxt.Diag("bad rrr %d", a)
  2586  	prasm(ctxt.Curp)
  2587  	return 0
  2588  }
  2589  
  2590  func opbra(ctxt *obj.Link, p *obj.Prog, a obj.As, sc int) uint32 {
  2591  	if sc&(C_SBIT|C_PBIT|C_WBIT) != 0 {
  2592  		ctxt.Diag("%v: .nil/.nil/.W on bra instruction", p)
  2593  	}
  2594  	sc &= C_SCOND
  2595  	sc ^= C_SCOND_XOR
  2596  	if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY {
  2597  		return uint32(sc)<<28 | 0x5<<25 | 0x1<<24
  2598  	}
  2599  	if sc != 0xe {
  2600  		ctxt.Diag("%v: .COND on bcond instruction", p)
  2601  	}
  2602  	switch a {
  2603  	case ABEQ:
  2604  		return 0x0<<28 | 0x5<<25
  2605  	case ABNE:
  2606  		return 0x1<<28 | 0x5<<25
  2607  	case ABCS:
  2608  		return 0x2<<28 | 0x5<<25
  2609  	case ABHS:
  2610  		return 0x2<<28 | 0x5<<25
  2611  	case ABCC:
  2612  		return 0x3<<28 | 0x5<<25
  2613  	case ABLO:
  2614  		return 0x3<<28 | 0x5<<25
  2615  	case ABMI:
  2616  		return 0x4<<28 | 0x5<<25
  2617  	case ABPL:
  2618  		return 0x5<<28 | 0x5<<25
  2619  	case ABVS:
  2620  		return 0x6<<28 | 0x5<<25
  2621  	case ABVC:
  2622  		return 0x7<<28 | 0x5<<25
  2623  	case ABHI:
  2624  		return 0x8<<28 | 0x5<<25
  2625  	case ABLS:
  2626  		return 0x9<<28 | 0x5<<25
  2627  	case ABGE:
  2628  		return 0xa<<28 | 0x5<<25
  2629  	case ABLT:
  2630  		return 0xb<<28 | 0x5<<25
  2631  	case ABGT:
  2632  		return 0xc<<28 | 0x5<<25
  2633  	case ABLE:
  2634  		return 0xd<<28 | 0x5<<25
  2635  	case AB:
  2636  		return 0xe<<28 | 0x5<<25
  2637  	}
  2638  
  2639  	ctxt.Diag("bad bra %v", a)
  2640  	prasm(ctxt.Curp)
  2641  	return 0
  2642  }
  2643  
  2644  func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
  2645  	if sc&C_SBIT != 0 {
  2646  		ctxt.Diag(".nil on LDR/STR instruction")
  2647  	}
  2648  	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
  2649  	if sc&C_PBIT == 0 {
  2650  		o |= 1 << 24
  2651  	}
  2652  	if sc&C_UBIT == 0 {
  2653  		o |= 1 << 23
  2654  	}
  2655  	if sc&C_WBIT != 0 {
  2656  		o |= 1 << 21
  2657  	}
  2658  	o |= 1<<26 | 1<<20
  2659  	if v < 0 {
  2660  		if sc&C_UBIT != 0 {
  2661  			ctxt.Diag(".U on neg offset")
  2662  		}
  2663  		v = -v
  2664  		o ^= 1 << 23
  2665  	}
  2666  
  2667  	if v >= 1<<12 || v < 0 {
  2668  		ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
  2669  	}
  2670  	o |= uint32(v)
  2671  	o |= (uint32(b) & 15) << 16
  2672  	o |= (uint32(r) & 15) << 12
  2673  	return o
  2674  }
  2675  
  2676  func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
  2677  	if sc&C_SBIT != 0 {
  2678  		ctxt.Diag(".nil on LDRH/STRH instruction")
  2679  	}
  2680  	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
  2681  	if sc&C_PBIT == 0 {
  2682  		o |= 1 << 24
  2683  	}
  2684  	if sc&C_WBIT != 0 {
  2685  		o |= 1 << 21
  2686  	}
  2687  	o |= 1<<23 | 1<<20 | 0xb<<4
  2688  	if v < 0 {
  2689  		v = -v
  2690  		o ^= 1 << 23
  2691  	}
  2692  
  2693  	if v >= 1<<8 || v < 0 {
  2694  		ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
  2695  	}
  2696  	o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22
  2697  	o |= (uint32(b) & 15) << 16
  2698  	o |= (uint32(r) & 15) << 12
  2699  	return o
  2700  }
  2701  
  2702  func osr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int) uint32 {
  2703  	o := olr(ctxt, v, b, r, sc) ^ (1 << 20)
  2704  	if a != AMOVW {
  2705  		o |= 1 << 22
  2706  	}
  2707  	return o
  2708  }
  2709  
  2710  func oshr(ctxt *obj.Link, r int, v int32, b int, sc int) uint32 {
  2711  	o := olhr(ctxt, v, b, r, sc) ^ (1 << 20)
  2712  	return o
  2713  }
  2714  
  2715  func osrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
  2716  	return olr(ctxt, int32(i), b, r, sc) ^ (1<<25 | 1<<20)
  2717  }
  2718  
  2719  func oshrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
  2720  	return olhr(ctxt, int32(i), b, r, sc) ^ (1<<22 | 1<<20)
  2721  }
  2722  
  2723  func olrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
  2724  	return olr(ctxt, int32(i), b, r, sc) ^ (1 << 25)
  2725  }
  2726  
  2727  func olhrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
  2728  	return olhr(ctxt, int32(i), b, r, sc) ^ (1 << 22)
  2729  }
  2730  
  2731  func ofsr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
  2732  	if sc&C_SBIT != 0 {
  2733  		ctxt.Diag(".nil on FLDR/FSTR instruction: %v", p)
  2734  	}
  2735  	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
  2736  	if sc&C_PBIT == 0 {
  2737  		o |= 1 << 24
  2738  	}
  2739  	if sc&C_WBIT != 0 {
  2740  		o |= 1 << 21
  2741  	}
  2742  	o |= 6<<25 | 1<<24 | 1<<23 | 10<<8
  2743  	if v < 0 {
  2744  		v = -v
  2745  		o ^= 1 << 23
  2746  	}
  2747  
  2748  	if v&3 != 0 {
  2749  		ctxt.Diag("odd offset for floating point op: %d\n%v", v, p)
  2750  	} else if v >= 1<<10 || v < 0 {
  2751  		ctxt.Diag("literal span too large: %d\n%v", v, p)
  2752  	}
  2753  	o |= (uint32(v) >> 2) & 0xFF
  2754  	o |= (uint32(b) & 15) << 16
  2755  	o |= (uint32(r) & 15) << 12
  2756  
  2757  	switch a {
  2758  	default:
  2759  		ctxt.Diag("bad fst %v", a)
  2760  		fallthrough
  2761  
  2762  	case AMOVD:
  2763  		o |= 1 << 8
  2764  		fallthrough
  2765  
  2766  	case AMOVF:
  2767  		break
  2768  	}
  2769  
  2770  	return o
  2771  }
  2772  
  2773  func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 {
  2774  	var o1 uint32
  2775  	if p.Pcond == nil {
  2776  		aclass(ctxt, a)
  2777  		v := immrot(^uint32(ctxt.Instoffset))
  2778  		if v == 0 {
  2779  			ctxt.Diag("missing literal")
  2780  			prasm(p)
  2781  			return 0
  2782  		}
  2783  
  2784  		o1 = oprrr(ctxt, AMVN, int(p.Scond)&C_SCOND)
  2785  		o1 |= uint32(v)
  2786  		o1 |= (uint32(dr) & 15) << 12
  2787  	} else {
  2788  		v := int32(p.Pcond.Pc - p.Pc - 8)
  2789  		o1 = olr(ctxt, v, REGPC, dr, int(p.Scond)&C_SCOND)
  2790  	}
  2791  
  2792  	return o1
  2793  }
  2794  
  2795  func chipzero5(ctxt *obj.Link, e float64) int {
  2796  	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
  2797  	if ctxt.Goarm < 7 || e != 0 {
  2798  		return -1
  2799  	}
  2800  	return 0
  2801  }
  2802  
  2803  func chipfloat5(ctxt *obj.Link, e float64) int {
  2804  	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
  2805  	if ctxt.Goarm < 7 {
  2806  		return -1
  2807  	}
  2808  
  2809  	ei := math.Float64bits(e)
  2810  	l := uint32(ei)
  2811  	h := uint32(ei >> 32)
  2812  
  2813  	if l != 0 || h&0xffff != 0 {
  2814  		return -1
  2815  	}
  2816  	h1 := h & 0x7fc00000
  2817  	if h1 != 0x40000000 && h1 != 0x3fc00000 {
  2818  		return -1
  2819  	}
  2820  	n := 0
  2821  
  2822  	// sign bit (a)
  2823  	if h&0x80000000 != 0 {
  2824  		n |= 1 << 7
  2825  	}
  2826  
  2827  	// exp sign bit (b)
  2828  	if h1 == 0x3fc00000 {
  2829  		n |= 1 << 6
  2830  	}
  2831  
  2832  	// rest of exp and mantissa (cd-efgh)
  2833  	n |= int((h >> 16) & 0x3f)
  2834  
  2835  	//print("match %.8lux %.8lux %d\n", l, h, n);
  2836  	return n
  2837  }
  2838  
  2839  func nocache(p *obj.Prog) {
  2840  	p.Optab = 0
  2841  	p.From.Class = 0
  2842  	if p.From3 != nil {
  2843  		p.From3.Class = 0
  2844  	}
  2845  	p.To.Class = 0
  2846  }