github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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  			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  }