github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/cmd/internal/obj/arm/asm5.go (about)

     1  // Inferno utils/5l/span.c
     2  // http://code.google.com/p/inferno-os/source/browse/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  			fmt.Fprintf(ctxt.Bso, "%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", obj.Aconv(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", obj.Aconv(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  
  1438  		case ACMPF:
  1439  			opset(ACMPD, r0)
  1440  
  1441  		case AMOVF:
  1442  			opset(AMOVD, r0)
  1443  
  1444  		case AMOVFW:
  1445  			opset(AMOVDW, r0)
  1446  
  1447  		case AMOVWF:
  1448  			opset(AMOVWD, r0)
  1449  
  1450  		case AMULL:
  1451  			opset(AMULAL, r0)
  1452  			opset(AMULLU, r0)
  1453  			opset(AMULALU, r0)
  1454  
  1455  		case AMULWT:
  1456  			opset(AMULWB, r0)
  1457  
  1458  		case AMULAWT:
  1459  			opset(AMULAWB, r0)
  1460  
  1461  		case AMULA,
  1462  			ALDREX,
  1463  			ASTREX,
  1464  			ALDREXD,
  1465  			ASTREXD,
  1466  			ATST,
  1467  			APLD,
  1468  			obj.AUNDEF,
  1469  			ACLZ,
  1470  			obj.AFUNCDATA,
  1471  			obj.APCDATA,
  1472  			obj.ANOP,
  1473  			ADATABUNDLE,
  1474  			ADATABUNDLEEND:
  1475  			break
  1476  		}
  1477  	}
  1478  }
  1479  
  1480  func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
  1481  	ctxt.Printp = p
  1482  	o1 := uint32(0)
  1483  	o2 := uint32(0)
  1484  	o3 := uint32(0)
  1485  	o4 := uint32(0)
  1486  	o5 := uint32(0)
  1487  	o6 := uint32(0)
  1488  	ctxt.Armsize += int32(o.size)
  1489  	if false { /*debug['P']*/
  1490  		fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_)
  1491  	}
  1492  	switch o.type_ {
  1493  	default:
  1494  		ctxt.Diag("unknown asm %d", o.type_)
  1495  		prasm(p)
  1496  
  1497  	case 0: /* pseudo ops */
  1498  		if false { /*debug['G']*/
  1499  			fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name)
  1500  		}
  1501  
  1502  	case 1: /* op R,[R],R */
  1503  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1504  
  1505  		rf := int(p.From.Reg)
  1506  		rt := int(p.To.Reg)
  1507  		r := int(p.Reg)
  1508  		if p.To.Type == obj.TYPE_NONE {
  1509  			rt = 0
  1510  		}
  1511  		if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN {
  1512  			r = 0
  1513  		} else if r == 0 {
  1514  			r = rt
  1515  		}
  1516  		o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
  1517  
  1518  	case 2: /* movbu $I,[R],R */
  1519  		aclass(ctxt, &p.From)
  1520  
  1521  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1522  		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
  1523  		rt := int(p.To.Reg)
  1524  		r := int(p.Reg)
  1525  		if p.To.Type == obj.TYPE_NONE {
  1526  			rt = 0
  1527  		}
  1528  		if p.As == AMOVW || p.As == AMVN {
  1529  			r = 0
  1530  		} else if r == 0 {
  1531  			r = rt
  1532  		}
  1533  		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
  1534  
  1535  	case 3: /* add R<<[IR],[R],R */
  1536  		o1 = mov(ctxt, p)
  1537  
  1538  	case 4: /* add $I,[R],R */
  1539  		aclass(ctxt, &p.From)
  1540  
  1541  		o1 = oprrr(ctxt, AADD, int(p.Scond))
  1542  		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
  1543  		r := int(p.From.Reg)
  1544  		if r == 0 {
  1545  			r = int(o.param)
  1546  		}
  1547  		o1 |= (uint32(r) & 15) << 16
  1548  		o1 |= (uint32(p.To.Reg) & 15) << 12
  1549  
  1550  	case 5: /* bra s */
  1551  		o1 = opbra(ctxt, p, p.As, int(p.Scond))
  1552  
  1553  		v := int32(-8)
  1554  		if p.To.Sym != nil {
  1555  			rel := obj.Addrel(ctxt.Cursym)
  1556  			rel.Off = int32(ctxt.Pc)
  1557  			rel.Siz = 4
  1558  			rel.Sym = p.To.Sym
  1559  			v += int32(p.To.Offset)
  1560  			rel.Add = int64(o1) | (int64(v)>>2)&0xffffff
  1561  			rel.Type = obj.R_CALLARM
  1562  			break
  1563  		}
  1564  
  1565  		if p.Pcond != nil {
  1566  			v = int32((p.Pcond.Pc - ctxt.Pc) - 8)
  1567  		}
  1568  		o1 |= (uint32(v) >> 2) & 0xffffff
  1569  
  1570  	case 6: /* b ,O(R) -> add $O,R,PC */
  1571  		aclass(ctxt, &p.To)
  1572  
  1573  		o1 = oprrr(ctxt, AADD, int(p.Scond))
  1574  		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
  1575  		o1 |= (uint32(p.To.Reg) & 15) << 16
  1576  		o1 |= (REGPC & 15) << 12
  1577  
  1578  	case 7: /* bl (R) -> blx R */
  1579  		aclass(ctxt, &p.To)
  1580  
  1581  		if ctxt.Instoffset != 0 {
  1582  			ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, ctxt.Instoffset)
  1583  		}
  1584  		o1 = oprrr(ctxt, ABL, int(p.Scond))
  1585  		o1 |= (uint32(p.To.Reg) & 15) << 0
  1586  		rel := obj.Addrel(ctxt.Cursym)
  1587  		rel.Off = int32(ctxt.Pc)
  1588  		rel.Siz = 0
  1589  		rel.Type = obj.R_CALLIND
  1590  
  1591  	case 8: /* sll $c,[R],R -> mov (R<<$c),R */
  1592  		aclass(ctxt, &p.From)
  1593  
  1594  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1595  		r := int(p.Reg)
  1596  		if r == 0 {
  1597  			r = int(p.To.Reg)
  1598  		}
  1599  		o1 |= (uint32(r) & 15) << 0
  1600  		o1 |= uint32((ctxt.Instoffset & 31) << 7)
  1601  		o1 |= (uint32(p.To.Reg) & 15) << 12
  1602  
  1603  	case 9: /* sll R,[R],R -> mov (R<<R),R */
  1604  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1605  
  1606  		r := int(p.Reg)
  1607  		if r == 0 {
  1608  			r = int(p.To.Reg)
  1609  		}
  1610  		o1 |= (uint32(r) & 15) << 0
  1611  		o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4
  1612  		o1 |= (uint32(p.To.Reg) & 15) << 12
  1613  
  1614  	case 10: /* swi [$con] */
  1615  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1616  
  1617  		if p.To.Type != obj.TYPE_NONE {
  1618  			aclass(ctxt, &p.To)
  1619  			o1 |= uint32(ctxt.Instoffset & 0xffffff)
  1620  		}
  1621  
  1622  	case 11: /* word */
  1623  		aclass(ctxt, &p.To)
  1624  
  1625  		o1 = uint32(ctxt.Instoffset)
  1626  		if p.To.Sym != nil {
  1627  			// This case happens with words generated
  1628  			// in the PC stream as part of the literal pool.
  1629  			rel := obj.Addrel(ctxt.Cursym)
  1630  
  1631  			rel.Off = int32(ctxt.Pc)
  1632  			rel.Siz = 4
  1633  			rel.Sym = p.To.Sym
  1634  			rel.Add = p.To.Offset
  1635  
  1636  			if ctxt.Flag_shared {
  1637  				if p.To.Name == obj.NAME_GOTREF {
  1638  					rel.Type = obj.R_GOTPCREL
  1639  				} else {
  1640  					rel.Type = obj.R_PCREL
  1641  				}
  1642  				rel.Add += ctxt.Pc - p.Rel.Pc - 8
  1643  			} else {
  1644  				rel.Type = obj.R_ADDR
  1645  			}
  1646  			o1 = 0
  1647  		}
  1648  
  1649  	case 12: /* movw $lcon, reg */
  1650  		o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
  1651  
  1652  		if o.flag&LPCREL != 0 {
  1653  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12
  1654  		}
  1655  
  1656  	case 13: /* op $lcon, [R], R */
  1657  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  1658  
  1659  		if o1 == 0 {
  1660  			break
  1661  		}
  1662  		o2 = oprrr(ctxt, p.As, int(p.Scond))
  1663  		o2 |= REGTMP & 15
  1664  		r := int(p.Reg)
  1665  		if p.As == AMOVW || p.As == AMVN {
  1666  			r = 0
  1667  		} else if r == 0 {
  1668  			r = int(p.To.Reg)
  1669  		}
  1670  		o2 |= (uint32(r) & 15) << 16
  1671  		if p.To.Type != obj.TYPE_NONE {
  1672  			o2 |= (uint32(p.To.Reg) & 15) << 12
  1673  		}
  1674  
  1675  	case 14: /* movb/movbu/movh/movhu R,R */
  1676  		o1 = oprrr(ctxt, ASLL, int(p.Scond))
  1677  
  1678  		if p.As == AMOVBU || p.As == AMOVHU {
  1679  			o2 = oprrr(ctxt, ASRL, int(p.Scond))
  1680  		} else {
  1681  			o2 = oprrr(ctxt, ASRA, int(p.Scond))
  1682  		}
  1683  
  1684  		r := int(p.To.Reg)
  1685  		o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12
  1686  		o2 |= uint32(r)&15 | (uint32(r)&15)<<12
  1687  		if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
  1688  			o1 |= 24 << 7
  1689  			o2 |= 24 << 7
  1690  		} else {
  1691  			o1 |= 16 << 7
  1692  			o2 |= 16 << 7
  1693  		}
  1694  
  1695  	case 15: /* mul r,[r,]r */
  1696  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1697  
  1698  		rf := int(p.From.Reg)
  1699  		rt := int(p.To.Reg)
  1700  		r := int(p.Reg)
  1701  		if r == 0 {
  1702  			r = rt
  1703  		}
  1704  		if rt == r {
  1705  			r = rf
  1706  			rf = rt
  1707  		}
  1708  
  1709  		if false {
  1710  			if rt == r || rf == REGPC&15 || r == REGPC&15 || rt == REGPC&15 {
  1711  				ctxt.Diag("bad registers in MUL")
  1712  				prasm(p)
  1713  			}
  1714  		}
  1715  
  1716  		o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
  1717  
  1718  	case 16: /* div r,[r,]r */
  1719  		o1 = 0xf << 28
  1720  
  1721  		o2 = 0
  1722  
  1723  	case 17:
  1724  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1725  		rf := int(p.From.Reg)
  1726  		rt := int(p.To.Reg)
  1727  		rt2 := int(p.To.Offset)
  1728  		r := int(p.Reg)
  1729  		o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12
  1730  
  1731  	case 20: /* mov/movb/movbu R,O(R) */
  1732  		aclass(ctxt, &p.To)
  1733  
  1734  		r := int(p.To.Reg)
  1735  		if r == 0 {
  1736  			r = int(o.param)
  1737  		}
  1738  		o1 = osr(ctxt, p.As, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
  1739  
  1740  	case 21: /* mov/movbu O(R),R -> lr */
  1741  		aclass(ctxt, &p.From)
  1742  
  1743  		r := int(p.From.Reg)
  1744  		if r == 0 {
  1745  			r = int(o.param)
  1746  		}
  1747  		o1 = olr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
  1748  		if p.As != AMOVW {
  1749  			o1 |= 1 << 22
  1750  		}
  1751  
  1752  	case 30: /* mov/movb/movbu R,L(R) */
  1753  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  1754  
  1755  		if o1 == 0 {
  1756  			break
  1757  		}
  1758  		r := int(p.To.Reg)
  1759  		if r == 0 {
  1760  			r = int(o.param)
  1761  		}
  1762  		o2 = osrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
  1763  		if p.As != AMOVW {
  1764  			o2 |= 1 << 22
  1765  		}
  1766  
  1767  	case 31: /* mov/movbu L(R),R -> lr[b] */
  1768  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  1769  
  1770  		if o1 == 0 {
  1771  			break
  1772  		}
  1773  		r := int(p.From.Reg)
  1774  		if r == 0 {
  1775  			r = int(o.param)
  1776  		}
  1777  		o2 = olrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
  1778  		if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
  1779  			o2 |= 1 << 22
  1780  		}
  1781  
  1782  	case 34: /* mov $lacon,R */
  1783  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  1784  
  1785  		if o1 == 0 {
  1786  			break
  1787  		}
  1788  
  1789  		o2 = oprrr(ctxt, AADD, int(p.Scond))
  1790  		o2 |= REGTMP & 15
  1791  		r := int(p.From.Reg)
  1792  		if r == 0 {
  1793  			r = int(o.param)
  1794  		}
  1795  		o2 |= (uint32(r) & 15) << 16
  1796  		if p.To.Type != obj.TYPE_NONE {
  1797  			o2 |= (uint32(p.To.Reg) & 15) << 12
  1798  		}
  1799  
  1800  	case 35: /* mov PSR,R */
  1801  		o1 = 2<<23 | 0xf<<16 | 0<<0
  1802  
  1803  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  1804  		o1 |= (uint32(p.From.Reg) & 1) << 22
  1805  		o1 |= (uint32(p.To.Reg) & 15) << 12
  1806  
  1807  	case 36: /* mov R,PSR */
  1808  		o1 = 2<<23 | 0x29f<<12 | 0<<4
  1809  
  1810  		if p.Scond&C_FBIT != 0 {
  1811  			o1 ^= 0x010 << 12
  1812  		}
  1813  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  1814  		o1 |= (uint32(p.To.Reg) & 1) << 22
  1815  		o1 |= (uint32(p.From.Reg) & 15) << 0
  1816  
  1817  	case 37: /* mov $con,PSR */
  1818  		aclass(ctxt, &p.From)
  1819  
  1820  		o1 = 2<<23 | 0x29f<<12 | 0<<4
  1821  		if p.Scond&C_FBIT != 0 {
  1822  			o1 ^= 0x010 << 12
  1823  		}
  1824  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  1825  		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
  1826  		o1 |= (uint32(p.To.Reg) & 1) << 22
  1827  		o1 |= (uint32(p.From.Reg) & 15) << 0
  1828  
  1829  	case 38, 39:
  1830  		switch o.type_ {
  1831  		case 38: /* movm $con,oreg -> stm */
  1832  			o1 = 0x4 << 25
  1833  
  1834  			o1 |= uint32(p.From.Offset & 0xffff)
  1835  			o1 |= (uint32(p.To.Reg) & 15) << 16
  1836  			aclass(ctxt, &p.To)
  1837  
  1838  		case 39: /* movm oreg,$con -> ldm */
  1839  			o1 = 0x4<<25 | 1<<20
  1840  
  1841  			o1 |= uint32(p.To.Offset & 0xffff)
  1842  			o1 |= (uint32(p.From.Reg) & 15) << 16
  1843  			aclass(ctxt, &p.From)
  1844  		}
  1845  
  1846  		if ctxt.Instoffset != 0 {
  1847  			ctxt.Diag("offset must be zero in MOVM; %v", p)
  1848  		}
  1849  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  1850  		if p.Scond&C_PBIT != 0 {
  1851  			o1 |= 1 << 24
  1852  		}
  1853  		if p.Scond&C_UBIT != 0 {
  1854  			o1 |= 1 << 23
  1855  		}
  1856  		if p.Scond&C_SBIT != 0 {
  1857  			o1 |= 1 << 22
  1858  		}
  1859  		if p.Scond&C_WBIT != 0 {
  1860  			o1 |= 1 << 21
  1861  		}
  1862  
  1863  	case 40: /* swp oreg,reg,reg */
  1864  		aclass(ctxt, &p.From)
  1865  
  1866  		if ctxt.Instoffset != 0 {
  1867  			ctxt.Diag("offset must be zero in SWP")
  1868  		}
  1869  		o1 = 0x2<<23 | 0x9<<4
  1870  		if p.As != ASWPW {
  1871  			o1 |= 1 << 22
  1872  		}
  1873  		o1 |= (uint32(p.From.Reg) & 15) << 16
  1874  		o1 |= (uint32(p.Reg) & 15) << 0
  1875  		o1 |= (uint32(p.To.Reg) & 15) << 12
  1876  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  1877  
  1878  	case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
  1879  		o1 = 0xe8fd8000
  1880  
  1881  	case 50: /* floating point store */
  1882  		v := regoff(ctxt, &p.To)
  1883  
  1884  		r := int(p.To.Reg)
  1885  		if r == 0 {
  1886  			r = int(o.param)
  1887  		}
  1888  		o1 = ofsr(ctxt, p.As, int(p.From.Reg), v, r, int(p.Scond), p)
  1889  
  1890  	case 51: /* floating point load */
  1891  		v := regoff(ctxt, &p.From)
  1892  
  1893  		r := int(p.From.Reg)
  1894  		if r == 0 {
  1895  			r = int(o.param)
  1896  		}
  1897  		o1 = ofsr(ctxt, p.As, int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20
  1898  
  1899  	case 52: /* floating point store, int32 offset UGLY */
  1900  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  1901  
  1902  		if o1 == 0 {
  1903  			break
  1904  		}
  1905  		r := int(p.To.Reg)
  1906  		if r == 0 {
  1907  			r = int(o.param)
  1908  		}
  1909  		o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
  1910  		o3 = ofsr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
  1911  
  1912  	case 53: /* floating point load, int32 offset UGLY */
  1913  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  1914  
  1915  		if o1 == 0 {
  1916  			break
  1917  		}
  1918  		r := int(p.From.Reg)
  1919  		if r == 0 {
  1920  			r = int(o.param)
  1921  		}
  1922  		o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
  1923  		o3 = ofsr(ctxt, p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
  1924  
  1925  	case 54: /* floating point arith */
  1926  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  1927  
  1928  		rf := int(p.From.Reg)
  1929  		rt := int(p.To.Reg)
  1930  		r := int(p.Reg)
  1931  		if r == 0 {
  1932  			r = rt
  1933  			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 {
  1934  				r = 0
  1935  			}
  1936  		}
  1937  
  1938  		o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
  1939  
  1940  	case 56: /* move to FP[CS]R */
  1941  		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
  1942  
  1943  		o1 |= ((uint32(p.To.Reg)&1)+1)<<21 | (uint32(p.From.Reg)&15)<<12
  1944  
  1945  	case 57: /* move from FP[CS]R */
  1946  		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
  1947  
  1948  		o1 |= ((uint32(p.From.Reg)&1)+1)<<21 | (uint32(p.To.Reg)&15)<<12 | 1<<20
  1949  
  1950  	case 58: /* movbu R,R */
  1951  		o1 = oprrr(ctxt, AAND, int(p.Scond))
  1952  
  1953  		o1 |= uint32(immrot(0xff))
  1954  		rt := int(p.To.Reg)
  1955  		r := int(p.From.Reg)
  1956  		if p.To.Type == obj.TYPE_NONE {
  1957  			rt = 0
  1958  		}
  1959  		if r == 0 {
  1960  			r = rt
  1961  		}
  1962  		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
  1963  
  1964  	case 59: /* movw/bu R<<I(R),R -> ldr indexed */
  1965  		if p.From.Reg == 0 {
  1966  			if p.As != AMOVW {
  1967  				ctxt.Diag("byte MOV from shifter operand")
  1968  			}
  1969  			o1 = mov(ctxt, p)
  1970  			break
  1971  		}
  1972  
  1973  		if p.From.Offset&(1<<4) != 0 {
  1974  			ctxt.Diag("bad shift in LDR")
  1975  		}
  1976  		o1 = olrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
  1977  		if p.As == AMOVBU {
  1978  			o1 |= 1 << 22
  1979  		}
  1980  
  1981  	case 60: /* movb R(R),R -> ldrsb indexed */
  1982  		if p.From.Reg == 0 {
  1983  			ctxt.Diag("byte MOV from shifter operand")
  1984  			o1 = mov(ctxt, p)
  1985  			break
  1986  		}
  1987  
  1988  		if p.From.Offset&(^0xf) != 0 {
  1989  			ctxt.Diag("bad shift in LDRSB")
  1990  		}
  1991  		o1 = olhrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
  1992  		o1 ^= 1<<5 | 1<<6
  1993  
  1994  	case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
  1995  		if p.To.Reg == 0 {
  1996  			ctxt.Diag("MOV to shifter operand")
  1997  		}
  1998  		o1 = osrr(ctxt, int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond))
  1999  		if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
  2000  			o1 |= 1 << 22
  2001  		}
  2002  
  2003  		/* reloc ops */
  2004  	case 64: /* mov/movb/movbu R,addr */
  2005  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  2006  
  2007  		if o1 == 0 {
  2008  			break
  2009  		}
  2010  		o2 = osr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond))
  2011  		if o.flag&LPCREL != 0 {
  2012  			o3 = o2
  2013  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2014  		}
  2015  
  2016  	case 65: /* mov/movbu addr,R */
  2017  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  2018  
  2019  		if o1 == 0 {
  2020  			break
  2021  		}
  2022  		o2 = olr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
  2023  		if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
  2024  			o2 |= 1 << 22
  2025  		}
  2026  		if o.flag&LPCREL != 0 {
  2027  			o3 = o2
  2028  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2029  		}
  2030  
  2031  	case 101: /* movw tlsvar,R, local exec*/
  2032  		if p.Scond&C_SCOND != C_SCOND_NONE {
  2033  			ctxt.Diag("conditional tls")
  2034  		}
  2035  		o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
  2036  
  2037  	case 102: /* movw tlsvar,R, initial exec*/
  2038  		if p.Scond&C_SCOND != C_SCOND_NONE {
  2039  			ctxt.Diag("conditional tls")
  2040  		}
  2041  		o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
  2042  		o2 = olrr(ctxt, int(p.To.Reg)&15, (REGPC & 15), int(p.To.Reg), int(p.Scond))
  2043  
  2044  	case 103: /* word tlsvar, local exec */
  2045  		if p.To.Sym == nil {
  2046  			ctxt.Diag("nil sym in tls %v", p)
  2047  		}
  2048  		if p.To.Offset != 0 {
  2049  			ctxt.Diag("offset against tls var in %v", p)
  2050  		}
  2051  		// This case happens with words generated in the PC stream as part of
  2052  		// the literal pool.
  2053  		rel := obj.Addrel(ctxt.Cursym)
  2054  
  2055  		rel.Off = int32(ctxt.Pc)
  2056  		rel.Siz = 4
  2057  		rel.Sym = p.To.Sym
  2058  		rel.Type = obj.R_TLS_LE
  2059  		o1 = 0
  2060  
  2061  	case 104: /* word tlsvar, initial exec */
  2062  		if p.To.Sym == nil {
  2063  			ctxt.Diag("nil sym in tls %v", p)
  2064  		}
  2065  		if p.To.Offset != 0 {
  2066  			ctxt.Diag("offset against tls var in %v", p)
  2067  		}
  2068  		rel := obj.Addrel(ctxt.Cursym)
  2069  		rel.Off = int32(ctxt.Pc)
  2070  		rel.Siz = 4
  2071  		rel.Sym = p.To.Sym
  2072  		rel.Type = obj.R_TLS_IE
  2073  		rel.Add = ctxt.Pc - p.Rel.Pc - 8 - int64(rel.Siz)
  2074  
  2075  	case 68: /* floating point store -> ADDR */
  2076  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  2077  
  2078  		if o1 == 0 {
  2079  			break
  2080  		}
  2081  		o2 = ofsr(ctxt, p.As, int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
  2082  		if o.flag&LPCREL != 0 {
  2083  			o3 = o2
  2084  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2085  		}
  2086  
  2087  	case 69: /* floating point load <- ADDR */
  2088  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  2089  
  2090  		if o1 == 0 {
  2091  			break
  2092  		}
  2093  		o2 = ofsr(ctxt, p.As, int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
  2094  		if o.flag&LPCREL != 0 {
  2095  			o3 = o2
  2096  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2097  		}
  2098  
  2099  		/* ArmV4 ops: */
  2100  	case 70: /* movh/movhu R,O(R) -> strh */
  2101  		aclass(ctxt, &p.To)
  2102  
  2103  		r := int(p.To.Reg)
  2104  		if r == 0 {
  2105  			r = int(o.param)
  2106  		}
  2107  		o1 = oshr(ctxt, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
  2108  
  2109  	case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
  2110  		aclass(ctxt, &p.From)
  2111  
  2112  		r := int(p.From.Reg)
  2113  		if r == 0 {
  2114  			r = int(o.param)
  2115  		}
  2116  		o1 = olhr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
  2117  		if p.As == AMOVB || p.As == AMOVBS {
  2118  			o1 ^= 1<<5 | 1<<6
  2119  		} else if p.As == AMOVH || p.As == AMOVHS {
  2120  			o1 ^= (1 << 6)
  2121  		}
  2122  
  2123  	case 72: /* movh/movhu R,L(R) -> strh */
  2124  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  2125  
  2126  		if o1 == 0 {
  2127  			break
  2128  		}
  2129  		r := int(p.To.Reg)
  2130  		if r == 0 {
  2131  			r = int(o.param)
  2132  		}
  2133  		o2 = oshrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
  2134  
  2135  	case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
  2136  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  2137  
  2138  		if o1 == 0 {
  2139  			break
  2140  		}
  2141  		r := int(p.From.Reg)
  2142  		if r == 0 {
  2143  			r = int(o.param)
  2144  		}
  2145  		o2 = olhrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
  2146  		if p.As == AMOVB || p.As == AMOVBS {
  2147  			o2 ^= 1<<5 | 1<<6
  2148  		} else if p.As == AMOVH || p.As == AMOVHS {
  2149  			o2 ^= (1 << 6)
  2150  		}
  2151  
  2152  	case 74: /* bx $I */
  2153  		ctxt.Diag("ABX $I")
  2154  
  2155  	case 75: /* bx O(R) */
  2156  		aclass(ctxt, &p.To)
  2157  
  2158  		if ctxt.Instoffset != 0 {
  2159  			ctxt.Diag("non-zero offset in ABX")
  2160  		}
  2161  
  2162  		/*
  2163  			o1 = 	oprrr(ctxt, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12);	// mov PC, LR
  2164  			o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0);		// BX R
  2165  		*/
  2166  		// p->to.reg may be REGLINK
  2167  		o1 = oprrr(ctxt, AADD, int(p.Scond))
  2168  
  2169  		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
  2170  		o1 |= (uint32(p.To.Reg) & 15) << 16
  2171  		o1 |= (REGTMP & 15) << 12
  2172  		o2 = oprrr(ctxt, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR
  2173  		o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15             // BX Rtmp
  2174  
  2175  	case 76: /* bx O(R) when returning from fn*/
  2176  		ctxt.Diag("ABXRET")
  2177  
  2178  	case 77: /* ldrex oreg,reg */
  2179  		aclass(ctxt, &p.From)
  2180  
  2181  		if ctxt.Instoffset != 0 {
  2182  			ctxt.Diag("offset must be zero in LDREX")
  2183  		}
  2184  		o1 = 0x19<<20 | 0xf9f
  2185  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2186  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2187  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2188  
  2189  	case 78: /* strex reg,oreg,reg */
  2190  		aclass(ctxt, &p.From)
  2191  
  2192  		if ctxt.Instoffset != 0 {
  2193  			ctxt.Diag("offset must be zero in STREX")
  2194  		}
  2195  		o1 = 0x18<<20 | 0xf90
  2196  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2197  		o1 |= (uint32(p.Reg) & 15) << 0
  2198  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2199  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2200  
  2201  	case 80: /* fmov zfcon,freg */
  2202  		if p.As == AMOVD {
  2203  			o1 = 0xeeb00b00 // VMOV imm 64
  2204  			o2 = oprrr(ctxt, ASUBD, int(p.Scond))
  2205  		} else {
  2206  			o1 = 0x0eb00a00 // VMOV imm 32
  2207  			o2 = oprrr(ctxt, ASUBF, int(p.Scond))
  2208  		}
  2209  
  2210  		v := int32(0x70) // 1.0
  2211  		r := (int(p.To.Reg) & 15) << 0
  2212  
  2213  		// movf $1.0, r
  2214  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2215  
  2216  		o1 |= (uint32(r) & 15) << 12
  2217  		o1 |= (uint32(v) & 0xf) << 0
  2218  		o1 |= (uint32(v) & 0xf0) << 12
  2219  
  2220  		// subf r,r,r
  2221  		o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12
  2222  
  2223  	case 81: /* fmov sfcon,freg */
  2224  		o1 = 0x0eb00a00 // VMOV imm 32
  2225  		if p.As == AMOVD {
  2226  			o1 = 0xeeb00b00 // VMOV imm 64
  2227  		}
  2228  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2229  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2230  		v := int32(chipfloat5(ctxt, p.From.Val.(float64)))
  2231  		o1 |= (uint32(v) & 0xf) << 0
  2232  		o1 |= (uint32(v) & 0xf0) << 12
  2233  
  2234  	case 82: /* fcmp freg,freg, */
  2235  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2236  
  2237  		o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0
  2238  		o2 = 0x0ef1fa10 // VMRS R15
  2239  		o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2240  
  2241  	case 83: /* fcmp freg,, */
  2242  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2243  
  2244  		o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16
  2245  		o2 = 0x0ef1fa10 // VMRS R15
  2246  		o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2247  
  2248  	case 84: /* movfw freg,freg - truncate float-to-fix */
  2249  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2250  
  2251  		o1 |= (uint32(p.From.Reg) & 15) << 0
  2252  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2253  
  2254  	case 85: /* movwf freg,freg - fix-to-float */
  2255  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2256  
  2257  		o1 |= (uint32(p.From.Reg) & 15) << 0
  2258  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2259  
  2260  		// macro for movfw freg,FTMP; movw FTMP,reg
  2261  	case 86: /* movfw freg,reg - truncate float-to-fix */
  2262  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2263  
  2264  		o1 |= (uint32(p.From.Reg) & 15) << 0
  2265  		o1 |= (FREGTMP & 15) << 12
  2266  		o2 = oprrr(ctxt, -AMOVFW, int(p.Scond))
  2267  		o2 |= (FREGTMP & 15) << 16
  2268  		o2 |= (uint32(p.To.Reg) & 15) << 12
  2269  
  2270  		// macro for movw reg,FTMP; movwf FTMP,freg
  2271  	case 87: /* movwf reg,freg - fix-to-float */
  2272  		o1 = oprrr(ctxt, -AMOVWF, int(p.Scond))
  2273  
  2274  		o1 |= (uint32(p.From.Reg) & 15) << 12
  2275  		o1 |= (FREGTMP & 15) << 16
  2276  		o2 = oprrr(ctxt, p.As, int(p.Scond))
  2277  		o2 |= (FREGTMP & 15) << 0
  2278  		o2 |= (uint32(p.To.Reg) & 15) << 12
  2279  
  2280  	case 88: /* movw reg,freg  */
  2281  		o1 = oprrr(ctxt, -AMOVWF, int(p.Scond))
  2282  
  2283  		o1 |= (uint32(p.From.Reg) & 15) << 12
  2284  		o1 |= (uint32(p.To.Reg) & 15) << 16
  2285  
  2286  	case 89: /* movw freg,reg  */
  2287  		o1 = oprrr(ctxt, -AMOVFW, int(p.Scond))
  2288  
  2289  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2290  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2291  
  2292  	case 90: /* tst reg  */
  2293  		o1 = oprrr(ctxt, -ACMP, int(p.Scond))
  2294  
  2295  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2296  
  2297  	case 91: /* ldrexd oreg,reg */
  2298  		aclass(ctxt, &p.From)
  2299  
  2300  		if ctxt.Instoffset != 0 {
  2301  			ctxt.Diag("offset must be zero in LDREX")
  2302  		}
  2303  		o1 = 0x1b<<20 | 0xf9f
  2304  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2305  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2306  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2307  
  2308  	case 92: /* strexd reg,oreg,reg */
  2309  		aclass(ctxt, &p.From)
  2310  
  2311  		if ctxt.Instoffset != 0 {
  2312  			ctxt.Diag("offset must be zero in STREX")
  2313  		}
  2314  		o1 = 0x1a<<20 | 0xf90
  2315  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2316  		o1 |= (uint32(p.Reg) & 15) << 0
  2317  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2318  		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
  2319  
  2320  	case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
  2321  		o1 = omvl(ctxt, p, &p.From, REGTMP)
  2322  
  2323  		if o1 == 0 {
  2324  			break
  2325  		}
  2326  		o2 = olhr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
  2327  		if p.As == AMOVB || p.As == AMOVBS {
  2328  			o2 ^= 1<<5 | 1<<6
  2329  		} else if p.As == AMOVH || p.As == AMOVHS {
  2330  			o2 ^= (1 << 6)
  2331  		}
  2332  		if o.flag&LPCREL != 0 {
  2333  			o3 = o2
  2334  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2335  		}
  2336  
  2337  	case 94: /* movh/movhu R,addr -> strh */
  2338  		o1 = omvl(ctxt, p, &p.To, REGTMP)
  2339  
  2340  		if o1 == 0 {
  2341  			break
  2342  		}
  2343  		o2 = oshr(ctxt, int(p.From.Reg), 0, REGTMP, int(p.Scond))
  2344  		if o.flag&LPCREL != 0 {
  2345  			o3 = o2
  2346  			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
  2347  		}
  2348  
  2349  	case 95: /* PLD off(reg) */
  2350  		o1 = 0xf5d0f000
  2351  
  2352  		o1 |= (uint32(p.From.Reg) & 15) << 16
  2353  		if p.From.Offset < 0 {
  2354  			o1 &^= (1 << 23)
  2355  			o1 |= uint32((-p.From.Offset) & 0xfff)
  2356  		} else {
  2357  			o1 |= uint32(p.From.Offset & 0xfff)
  2358  		}
  2359  
  2360  		// This is supposed to be something that stops execution.
  2361  	// It's not supposed to be reached, ever, but if it is, we'd
  2362  	// like to be able to tell how we got there. Assemble as
  2363  	// 0xf7fabcfd which is guaranteed to raise undefined instruction
  2364  	// exception.
  2365  	case 96: /* UNDEF */
  2366  		o1 = 0xf7fabcfd
  2367  
  2368  	case 97: /* CLZ Rm, Rd */
  2369  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2370  
  2371  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2372  		o1 |= (uint32(p.From.Reg) & 15) << 0
  2373  
  2374  	case 98: /* MULW{T,B} Rs, Rm, Rd */
  2375  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2376  
  2377  		o1 |= (uint32(p.To.Reg) & 15) << 16
  2378  		o1 |= (uint32(p.From.Reg) & 15) << 8
  2379  		o1 |= (uint32(p.Reg) & 15) << 0
  2380  
  2381  	case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
  2382  		o1 = oprrr(ctxt, p.As, int(p.Scond))
  2383  
  2384  		o1 |= (uint32(p.To.Reg) & 15) << 12
  2385  		o1 |= (uint32(p.From.Reg) & 15) << 8
  2386  		o1 |= (uint32(p.Reg) & 15) << 0
  2387  		o1 |= uint32((p.To.Offset & 15) << 16)
  2388  
  2389  		// DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
  2390  	// DATABUNDLEEND: zero width alignment marker
  2391  	case 100:
  2392  		if p.As == ADATABUNDLE {
  2393  			o1 = 0xe125be70
  2394  		}
  2395  	}
  2396  
  2397  	out[0] = o1
  2398  	out[1] = o2
  2399  	out[2] = o3
  2400  	out[3] = o4
  2401  	out[4] = o5
  2402  	out[5] = o6
  2403  	return
  2404  }
  2405  
  2406  func mov(ctxt *obj.Link, p *obj.Prog) uint32 {
  2407  	aclass(ctxt, &p.From)
  2408  	o1 := oprrr(ctxt, p.As, int(p.Scond))
  2409  	o1 |= uint32(p.From.Offset)
  2410  	rt := int(p.To.Reg)
  2411  	if p.To.Type == obj.TYPE_NONE {
  2412  		rt = 0
  2413  	}
  2414  	r := int(p.Reg)
  2415  	if p.As == AMOVW || p.As == AMVN {
  2416  		r = 0
  2417  	} else if r == 0 {
  2418  		r = rt
  2419  	}
  2420  	o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
  2421  	return o1
  2422  }
  2423  
  2424  func oprrr(ctxt *obj.Link, a obj.As, sc int) uint32 {
  2425  	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
  2426  	if sc&C_SBIT != 0 {
  2427  		o |= 1 << 20
  2428  	}
  2429  	if sc&(C_PBIT|C_WBIT) != 0 {
  2430  		ctxt.Diag(".nil/.W on dp instruction")
  2431  	}
  2432  	switch a {
  2433  	case AMULU, AMUL:
  2434  		return o | 0x0<<21 | 0x9<<4
  2435  	case AMULA:
  2436  		return o | 0x1<<21 | 0x9<<4
  2437  	case AMULLU:
  2438  		return o | 0x4<<21 | 0x9<<4
  2439  	case AMULL:
  2440  		return o | 0x6<<21 | 0x9<<4
  2441  	case AMULALU:
  2442  		return o | 0x5<<21 | 0x9<<4
  2443  	case AMULAL:
  2444  		return o | 0x7<<21 | 0x9<<4
  2445  	case AAND:
  2446  		return o | 0x0<<21
  2447  	case AEOR:
  2448  		return o | 0x1<<21
  2449  	case ASUB:
  2450  		return o | 0x2<<21
  2451  	case ARSB:
  2452  		return o | 0x3<<21
  2453  	case AADD:
  2454  		return o | 0x4<<21
  2455  	case AADC:
  2456  		return o | 0x5<<21
  2457  	case ASBC:
  2458  		return o | 0x6<<21
  2459  	case ARSC:
  2460  		return o | 0x7<<21
  2461  	case ATST:
  2462  		return o | 0x8<<21 | 1<<20
  2463  	case ATEQ:
  2464  		return o | 0x9<<21 | 1<<20
  2465  	case ACMP:
  2466  		return o | 0xa<<21 | 1<<20
  2467  	case ACMN:
  2468  		return o | 0xb<<21 | 1<<20
  2469  	case AORR:
  2470  		return o | 0xc<<21
  2471  
  2472  	case AMOVB, AMOVH, AMOVW:
  2473  		return o | 0xd<<21
  2474  	case ABIC:
  2475  		return o | 0xe<<21
  2476  	case AMVN:
  2477  		return o | 0xf<<21
  2478  	case ASLL:
  2479  		return o | 0xd<<21 | 0<<5
  2480  	case ASRL:
  2481  		return o | 0xd<<21 | 1<<5
  2482  	case ASRA:
  2483  		return o | 0xd<<21 | 2<<5
  2484  	case ASWI:
  2485  		return o | 0xf<<24
  2486  
  2487  	case AADDD:
  2488  		return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4
  2489  	case AADDF:
  2490  		return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4
  2491  	case ASUBD:
  2492  		return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4
  2493  	case ASUBF:
  2494  		return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4
  2495  	case AMULD:
  2496  		return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4
  2497  	case AMULF:
  2498  		return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4
  2499  	case ADIVD:
  2500  		return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4
  2501  	case ADIVF:
  2502  		return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4
  2503  	case ASQRTD:
  2504  		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4
  2505  	case ASQRTF:
  2506  		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4
  2507  	case AABSD:
  2508  		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4
  2509  	case AABSF:
  2510  		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4
  2511  	case ACMPD:
  2512  		return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4
  2513  	case ACMPF:
  2514  		return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4
  2515  
  2516  	case AMOVF:
  2517  		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4
  2518  	case AMOVD:
  2519  		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4
  2520  
  2521  	case AMOVDF:
  2522  		return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof
  2523  	case AMOVFD:
  2524  		return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof
  2525  
  2526  	case AMOVWF:
  2527  		if sc&C_UBIT == 0 {
  2528  			o |= 1 << 7 /* signed */
  2529  		}
  2530  		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double
  2531  
  2532  	case AMOVWD:
  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 | 1<<8 // toint, double
  2537  
  2538  	case AMOVFW:
  2539  		if sc&C_UBIT == 0 {
  2540  			o |= 1 << 16 /* signed */
  2541  		}
  2542  		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc
  2543  
  2544  	case AMOVDW:
  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 | 1<<8 | 1<<7 // toint, double, trunc
  2549  
  2550  	case -AMOVWF: // copy WtoF
  2551  		return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4
  2552  
  2553  	case -AMOVFW: // copy FtoW
  2554  		return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4
  2555  
  2556  	case -ACMP: // cmp imm
  2557  		return o | 0x3<<24 | 0x5<<20
  2558  
  2559  		// CLZ doesn't support .nil
  2560  	case ACLZ:
  2561  		return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4
  2562  
  2563  	case AMULWT:
  2564  		return o&(0xf<<28) | 0x12<<20 | 0xe<<4
  2565  
  2566  	case AMULWB:
  2567  		return o&(0xf<<28) | 0x12<<20 | 0xa<<4
  2568  
  2569  	case AMULAWT:
  2570  		return o&(0xf<<28) | 0x12<<20 | 0xc<<4
  2571  
  2572  	case AMULAWB:
  2573  		return o&(0xf<<28) | 0x12<<20 | 0x8<<4
  2574  
  2575  	case ABL: // BLX REG
  2576  		return o&(0xf<<28) | 0x12fff3<<4
  2577  	}
  2578  
  2579  	ctxt.Diag("bad rrr %d", a)
  2580  	prasm(ctxt.Curp)
  2581  	return 0
  2582  }
  2583  
  2584  func opbra(ctxt *obj.Link, p *obj.Prog, a obj.As, sc int) uint32 {
  2585  	if sc&(C_SBIT|C_PBIT|C_WBIT) != 0 {
  2586  		ctxt.Diag("%v: .nil/.nil/.W on bra instruction", p)
  2587  	}
  2588  	sc &= C_SCOND
  2589  	sc ^= C_SCOND_XOR
  2590  	if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY {
  2591  		return uint32(sc)<<28 | 0x5<<25 | 0x1<<24
  2592  	}
  2593  	if sc != 0xe {
  2594  		ctxt.Diag("%v: .COND on bcond instruction", p)
  2595  	}
  2596  	switch a {
  2597  	case ABEQ:
  2598  		return 0x0<<28 | 0x5<<25
  2599  	case ABNE:
  2600  		return 0x1<<28 | 0x5<<25
  2601  	case ABCS:
  2602  		return 0x2<<28 | 0x5<<25
  2603  	case ABHS:
  2604  		return 0x2<<28 | 0x5<<25
  2605  	case ABCC:
  2606  		return 0x3<<28 | 0x5<<25
  2607  	case ABLO:
  2608  		return 0x3<<28 | 0x5<<25
  2609  	case ABMI:
  2610  		return 0x4<<28 | 0x5<<25
  2611  	case ABPL:
  2612  		return 0x5<<28 | 0x5<<25
  2613  	case ABVS:
  2614  		return 0x6<<28 | 0x5<<25
  2615  	case ABVC:
  2616  		return 0x7<<28 | 0x5<<25
  2617  	case ABHI:
  2618  		return 0x8<<28 | 0x5<<25
  2619  	case ABLS:
  2620  		return 0x9<<28 | 0x5<<25
  2621  	case ABGE:
  2622  		return 0xa<<28 | 0x5<<25
  2623  	case ABLT:
  2624  		return 0xb<<28 | 0x5<<25
  2625  	case ABGT:
  2626  		return 0xc<<28 | 0x5<<25
  2627  	case ABLE:
  2628  		return 0xd<<28 | 0x5<<25
  2629  	case AB:
  2630  		return 0xe<<28 | 0x5<<25
  2631  	}
  2632  
  2633  	ctxt.Diag("bad bra %v", obj.Aconv(a))
  2634  	prasm(ctxt.Curp)
  2635  	return 0
  2636  }
  2637  
  2638  func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
  2639  	if sc&C_SBIT != 0 {
  2640  		ctxt.Diag(".nil on LDR/STR instruction")
  2641  	}
  2642  	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
  2643  	if sc&C_PBIT == 0 {
  2644  		o |= 1 << 24
  2645  	}
  2646  	if sc&C_UBIT == 0 {
  2647  		o |= 1 << 23
  2648  	}
  2649  	if sc&C_WBIT != 0 {
  2650  		o |= 1 << 21
  2651  	}
  2652  	o |= 1<<26 | 1<<20
  2653  	if v < 0 {
  2654  		if sc&C_UBIT != 0 {
  2655  			ctxt.Diag(".U on neg offset")
  2656  		}
  2657  		v = -v
  2658  		o ^= 1 << 23
  2659  	}
  2660  
  2661  	if v >= 1<<12 || v < 0 {
  2662  		ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
  2663  	}
  2664  	o |= uint32(v)
  2665  	o |= (uint32(b) & 15) << 16
  2666  	o |= (uint32(r) & 15) << 12
  2667  	return o
  2668  }
  2669  
  2670  func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
  2671  	if sc&C_SBIT != 0 {
  2672  		ctxt.Diag(".nil on LDRH/STRH instruction")
  2673  	}
  2674  	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
  2675  	if sc&C_PBIT == 0 {
  2676  		o |= 1 << 24
  2677  	}
  2678  	if sc&C_WBIT != 0 {
  2679  		o |= 1 << 21
  2680  	}
  2681  	o |= 1<<23 | 1<<20 | 0xb<<4
  2682  	if v < 0 {
  2683  		v = -v
  2684  		o ^= 1 << 23
  2685  	}
  2686  
  2687  	if v >= 1<<8 || v < 0 {
  2688  		ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
  2689  	}
  2690  	o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22
  2691  	o |= (uint32(b) & 15) << 16
  2692  	o |= (uint32(r) & 15) << 12
  2693  	return o
  2694  }
  2695  
  2696  func osr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int) uint32 {
  2697  	o := olr(ctxt, v, b, r, sc) ^ (1 << 20)
  2698  	if a != AMOVW {
  2699  		o |= 1 << 22
  2700  	}
  2701  	return o
  2702  }
  2703  
  2704  func oshr(ctxt *obj.Link, r int, v int32, b int, sc int) uint32 {
  2705  	o := olhr(ctxt, v, b, r, sc) ^ (1 << 20)
  2706  	return o
  2707  }
  2708  
  2709  func osrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
  2710  	return olr(ctxt, int32(i), b, r, sc) ^ (1<<25 | 1<<20)
  2711  }
  2712  
  2713  func oshrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
  2714  	return olhr(ctxt, int32(i), b, r, sc) ^ (1<<22 | 1<<20)
  2715  }
  2716  
  2717  func olrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
  2718  	return olr(ctxt, int32(i), b, r, sc) ^ (1 << 25)
  2719  }
  2720  
  2721  func olhrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
  2722  	return olhr(ctxt, int32(i), b, r, sc) ^ (1 << 22)
  2723  }
  2724  
  2725  func ofsr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
  2726  	if sc&C_SBIT != 0 {
  2727  		ctxt.Diag(".nil on FLDR/FSTR instruction: %v", p)
  2728  	}
  2729  	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
  2730  	if sc&C_PBIT == 0 {
  2731  		o |= 1 << 24
  2732  	}
  2733  	if sc&C_WBIT != 0 {
  2734  		o |= 1 << 21
  2735  	}
  2736  	o |= 6<<25 | 1<<24 | 1<<23 | 10<<8
  2737  	if v < 0 {
  2738  		v = -v
  2739  		o ^= 1 << 23
  2740  	}
  2741  
  2742  	if v&3 != 0 {
  2743  		ctxt.Diag("odd offset for floating point op: %d\n%v", v, p)
  2744  	} else if v >= 1<<10 || v < 0 {
  2745  		ctxt.Diag("literal span too large: %d\n%v", v, p)
  2746  	}
  2747  	o |= (uint32(v) >> 2) & 0xFF
  2748  	o |= (uint32(b) & 15) << 16
  2749  	o |= (uint32(r) & 15) << 12
  2750  
  2751  	switch a {
  2752  	default:
  2753  		ctxt.Diag("bad fst %v", obj.Aconv(a))
  2754  		fallthrough
  2755  
  2756  	case AMOVD:
  2757  		o |= 1 << 8
  2758  		fallthrough
  2759  
  2760  	case AMOVF:
  2761  		break
  2762  	}
  2763  
  2764  	return o
  2765  }
  2766  
  2767  func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 {
  2768  	var o1 uint32
  2769  	if p.Pcond == nil {
  2770  		aclass(ctxt, a)
  2771  		v := immrot(^uint32(ctxt.Instoffset))
  2772  		if v == 0 {
  2773  			ctxt.Diag("missing literal")
  2774  			prasm(p)
  2775  			return 0
  2776  		}
  2777  
  2778  		o1 = oprrr(ctxt, AMVN, int(p.Scond)&C_SCOND)
  2779  		o1 |= uint32(v)
  2780  		o1 |= (uint32(dr) & 15) << 12
  2781  	} else {
  2782  		v := int32(p.Pcond.Pc - p.Pc - 8)
  2783  		o1 = olr(ctxt, v, REGPC, dr, int(p.Scond)&C_SCOND)
  2784  	}
  2785  
  2786  	return o1
  2787  }
  2788  
  2789  func chipzero5(ctxt *obj.Link, e float64) int {
  2790  	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
  2791  	if ctxt.Goarm < 7 || e != 0 {
  2792  		return -1
  2793  	}
  2794  	return 0
  2795  }
  2796  
  2797  func chipfloat5(ctxt *obj.Link, e float64) int {
  2798  	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
  2799  	if ctxt.Goarm < 7 {
  2800  		return -1
  2801  	}
  2802  
  2803  	ei := math.Float64bits(e)
  2804  	l := uint32(ei)
  2805  	h := uint32(ei >> 32)
  2806  
  2807  	if l != 0 || h&0xffff != 0 {
  2808  		return -1
  2809  	}
  2810  	h1 := h & 0x7fc00000
  2811  	if h1 != 0x40000000 && h1 != 0x3fc00000 {
  2812  		return -1
  2813  	}
  2814  	n := 0
  2815  
  2816  	// sign bit (a)
  2817  	if h&0x80000000 != 0 {
  2818  		n |= 1 << 7
  2819  	}
  2820  
  2821  	// exp sign bit (b)
  2822  	if h1 == 0x3fc00000 {
  2823  		n |= 1 << 6
  2824  	}
  2825  
  2826  	// rest of exp and mantissa (cd-efgh)
  2827  	n |= int((h >> 16) & 0x3f)
  2828  
  2829  	//print("match %.8lux %.8lux %d\n", l, h, n);
  2830  	return n
  2831  }
  2832  
  2833  func nocache(p *obj.Prog) {
  2834  	p.Optab = 0
  2835  	p.From.Class = 0
  2836  	if p.From3 != nil {
  2837  		p.From3.Class = 0
  2838  	}
  2839  	p.To.Class = 0
  2840  }