github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/src/cmd/internal/obj/arm/asm5.go (about)

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