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