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