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