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