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