]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/7l/asmout.c
libtags, zuke: add *.mod support (thanks kemal)
[plan9front.git] / sys / src / cmd / 7l / asmout.c
1 #include        "l.h"
2
3 #define S32     (0U<<31)
4 #define S64     (1U<<31)
5 #define Rm(X)   (((X)&31)<<16)
6 #define Rn(X)   (((X)&31)<<5)
7 #define Rd(X)   (((X)&31)<<0)
8 #define Sbit    (1U<<29)
9
10 #define OPDP2(x)                (0<<30 | 0 << 29 | 0xd6<<21 | (x)<<10)
11 #define OPDP3(sf,op54,op31,o0)  ((sf)<<31 | (op54)<<29 | 0x1B<<24 | (op31)<<21 | (o0)<<15)
12 #define OPBcc(x)                (0x2A<<25 | 0<<24 | 0<<4 | ((x)&15))
13 #define OPBLR(x)                (0x6B<<25 | 0<<23 | (x)<<21 | 0x1F<<16 | 0<<10) /* x=0, JMP; 1, CALL; 2, RET */
14 #define SYSOP(l,op0,op1,crn,crm,op2,rt) (0x354<<22 | (l)<<21 | (op0)<<19 | (op1)<<16 | (crn)<<12 | (crm)<<8 | (op2)<<5 | (rt))
15 #define SYSHINT(x)      SYSOP(0,0,3,2,0,(x),0x1F)
16
17 #define LDSTR12U(sz,v,opc)      ((sz)<<30 | 7<<27 | (v)<<26 | 1<<24 | (opc)<<22)
18 #define LDSTR9S(sz,v,opc)       ((sz)<<30 | 7<<27 | (v)<<26 | 0<<24 | (opc)<<22)
19 #define LD2STR(o)       ((o) & ~(3<<22))
20
21 #define LDSTX(sz,o2,l,o1,o0)    ((sz)<<30 | 0x8<<24 | (o2)<<23 | (l)<<22 | (o1)<<21 | (o0)<<15)
22
23 #define FPCMP(m,s,type,op,op2)  ((m)<<31 | (s)<<29 | 0x1E<<24 | (type)<<22 | 1<<21 | (op)<<14 | 8<<10 | (op2))
24 #define FPCCMP(m,s,type,op)     ((m)<<31 | (s)<<29 | 0x1E<<24 | (type)<<22 | 1<<21 | 1<<10 | (op)<<4)
25 #define FPOP1S(m,s,type,op)     ((m)<<31 | (s)<<29 | 0x1E<<24 | (type)<<22 | 1<<21 | (op)<<15 | 0x10<<10)
26 #define FPOP2S(m,s,type,op)     ((m)<<31 | (s)<<29 | 0x1E<<24 | (type)<<22 | 1<<21 | (op)<<12 | 2<<10)
27 #define FPCVTI(sf,s,type,rmode,op)      ((sf)<<31 | (s)<<29 | 0x1E<<24 | (type)<<22 | 1<<21 | (rmode)<<19 | (op)<<16 | 0<<10)
28 #define FPCVTF(sf,s,type,rmode,op,scale)        ((sf)<<31 | (s)<<29 | 0x1E<<24 | (type)<<22 | 0<<21 | (rmode)<<19 | (op)<<16 | (scale)<<10)
29 #define ADR(p,o,rt)     ((p)<<31 | ((o)&3)<<29 | (0x10<<24) | (((o>>2)&0x7FFFF)<<5) | (rt))
30
31 #define LSL0_32 (2<<13)
32 #define LSL0_64 (3<<13)
33
34 static long     opbrr(int);
35 static long     opbra(int);
36 static long     oshrr(int, int, int);
37 static long     olhrr(int, int, int);
38 static long     olsr12u(long, long, int, int);
39 static long     olsr9s(long, long, int, int);
40 static long     opimm(int);
41 static vlong    brdist(Prog*, int, int, int);
42 static long     opbfm(int, int, int, int, int);
43 static long     opextr(int, long, int, int, int);
44 static long     opbit(int);
45 static long     op0(int);
46 static long     opstr12(int);
47 static long     opstr9(int);
48 static long     opldr9(int);
49 static long     opxrrr(int);
50 static long     olsxrr(int, int, int, int);
51 static long     oprrr(int);
52 static long     opirr(int);
53 static long     opldr12(int);
54 static long     opldrpp(int);
55 static long     opload(int);
56 static long     opstore(int);
57 static long     omovlit(int, Prog*, Adr*, int);
58 static int      movesize(int);
59 static long     oaddi(long, long, int, int);
60
61 /*
62  * valid pstate field values, and value to use in instruction
63  */
64 static struct{
65         ulong   a;
66         ulong   b;
67 } pstatefield[] = {
68 D_SPSel,                (0<<16) | (4<<12) | (5<<5),
69 D_DAIFSet,      (3<<16) | (4<<12) | (6<<5),
70 D_DAIFClr,      (3<<16) | (4<<12) | (7<<5),
71 };
72
73 void
74 asmout(Prog *p, Optab *o)
75 {
76         long o1, o2, o3, o4, o5, v, hi;
77         vlong d;
78         int r, s, rf, rt, ra, nzcv, cond, i, as;
79         Mask *mask;
80         static Prog *lastcase;
81
82         o1 = 0;
83         o2 = 0;
84         o3 = 0;
85         o4 = 0;
86         o5 = 0;
87         switch(o->type) {
88         default:
89                 diag("unknown asm %d", o->type);
90                 prasm(p);
91                 break;
92
93         case 0:         /* pseudo ops */
94                 break;
95
96         case 1:         /* op Rm,[Rn],Rd; default Rn=Rd -> op Rm<<0,[Rn,]Rd (shifted register) */
97                 o1 = oprrr(p->as);
98                 rf = p->from.reg;
99                 rt = p->to.reg;
100                 r = p->reg;
101                 if(p->to.type == D_NONE)
102                         rt = REGZERO;
103                 if(r == NREG)
104                         r = rt;
105                 o1 |= (rf<<16) | (r<<5) | rt;
106                 break;
107
108         case 2:         /* add/sub $(uimm12|uimm24)[,R],R; cmp $(uimm12|uimm24),R */
109                 o1 = opirr(p->as);
110                 rt = p->to.reg;
111                 if(p->to.type == D_NONE){
112                         if((o1 & Sbit) == 0)
113                                 diag("ineffective ZR destination\n%P", p);
114                         rt = REGZERO;
115                 }
116                 r = p->reg;
117                 if(r == NREG)
118                         r = rt;
119                 v = regoff(&p->from);
120                 o1 = oaddi(o1, v, r, rt);
121                 break;
122
123         case 3:         /* op R<<n[,R],R (shifted register) */
124                 o1 = oprrr(p->as);
125                 o1 |= p->from.offset;   /* includes reg, op, etc */
126                 rt = p->to.reg;
127                 if(p->to.type == D_NONE)
128                         rt = REGZERO;
129                 r = p->reg;
130                 if(p->as == AMVN || p->as == AMVNW)
131                         r = REGZERO;
132                 else if(r == NREG)
133                         r = rt;
134                 o1 |= (r<<5) | rt;
135                 break;
136
137         case 4:         /* mov $addcon, R; mov $recon, R; mov $racon, R */
138                 o1 = opirr(p->as);
139                 rt = p->to.reg;
140                 r = o->param;
141                 if(r == 0)
142                         r = REGZERO;
143                 v = regoff(&p->from);
144                 if((v & 0xFFF000) != 0){
145                         v >>= 12;
146                         o1 |= 1<<22;    /* shift, by 12 */
147                 }
148                 o1 |= ((v& 0xFFF) << 10) | (r<<5) | rt;
149                 break;
150
151         case 5:         /* b s; bl s */
152                 o1 = opbra(p->as);
153                 o1 |= brdist(p, 0, 26, 2);
154                 break;
155
156         case 6:         /* b ,O(R); bl ,O(R) */
157                 o1 = opbrr(p->as);
158                 o1 |= p->to.reg << 5;
159                 break;
160
161         case 7:         /* beq s */
162                 o1 = opbra(p->as);
163                 o1 |= brdist(p, 0, 19, 2)<<5;
164                 break;
165
166         case 8:         /* lsl $c,[R],R -> ubfm $(W-1)-c,$(-c MOD (W-1)),Rn,Rd */
167                 rt = p->to.reg;
168                 rf = p->reg;
169                 if(rf == NREG)
170                         rf = rt;
171                 v = p->from.offset;
172                 switch(p->as){
173                 case AASR:      o1 = opbfm(ASBFM, v, 63, rf, rt); break;
174                 case AASRW:     o1 = opbfm(ASBFMW, v, 31, rf, rt); break;
175                 case ALSL:      o1 = opbfm(AUBFM, (64-v)&63, 63-v, rf, rt); break;
176                 case ALSLW:     o1 = opbfm(AUBFMW, (32-v)&31, 31-v, rf, rt); break;
177                 case ALSR:      o1 = opbfm(AUBFM, v, 63, rf, rt); break;
178                 case ALSRW:     o1 = opbfm(AUBFMW, v, 31, rf, rt); break;
179                 case AROR:      o1 = opextr(AEXTR, v, rf, rf, rt); break;
180                 case ARORW:     o1 = opextr(AEXTRW, v, rf, rf, rt); break;
181                 default:
182                         diag("bad shift $con\n%P", curp);
183                         break;
184                 }
185                 break;
186
187         case 9:         /* lsl Rm,[Rn],Rd -> lslv Rm, Rn, Rd */
188                 o1 = oprrr(p->as);
189                 r = p->reg;
190                 if(r == NREG)
191                         r = p->to.reg;
192                 o1 |= (p->from.reg << 16) | (r<<5) | p->to.reg;
193                 break;
194
195         case 10:        /* brk/hvc/.../svc [$con] */
196                 o1 = opimm(p->as);
197                 if(p->to.type != D_NONE)
198                         o1 |= (p->to.offset & 0xffff)<<5;
199                 break;
200
201         case 11:        /* dword */
202                 switch(aclass(&p->to)) {
203                 case C_VCON:
204                 case C_ZCON:
205                 case C_LCON:
206                         if(!dlm)
207                                 break;
208                         if(p->to.name != D_EXTERN && p->to.name != D_STATIC)
209                                 break;
210                 case C_ADDR:
211                         if(p->to.sym->type == SUNDEF)
212                                 ckoff(p->to.sym, p->to.offset);
213                         dynreloc(p->to.sym, p->pc, 1);
214                 }
215                 o1 = instoffset;
216                 o2 = instoffset >> 32;
217                 break;
218
219         case 12:        /* movT $lcon, reg */
220                 o1 = omovlit(p->as, p, &p->from, p->to.reg);
221                 break;
222
223         case 13:        /* addop $lcon, [R], R (64 bit literal); cmp $lcon,R -> addop $lcon,R, ZR */
224                 o1 = omovlit(AMOV, p, &p->from, REGTMP);
225                 rt = p->to.reg;
226                 if(p->to.type == D_NONE)
227                         rt = REGZERO;
228                 r = p->reg;
229                 if(r == NREG)
230                         r = rt;
231                 if(p->to.type != D_NONE && (p->to.reg == REGSP || r == REGSP)){
232                         o2 = opxrrr(p->as);
233                         o2 |= REGTMP<<16;
234                         o2 |= LSL0_64;
235                 }else{
236                         o2 = oprrr(p->as);
237                         o2 |= REGTMP << 16;     /* shift is 0 */
238                 }
239                 o2 |= r << 5;
240                 o2 |= rt;
241                 break;
242
243         case 14:        /* word */
244                 if(aclass(&p->to) == C_ADDR)
245                         diag("address constant needs DWORD\n%P", p);
246                 o1 = instoffset;
247                 break;
248
249         case 15:        /* mul/mneg/umulh/umull r,[r,]r; madd/msub Rm,Rn,Ra,Rd */
250                 o1 = oprrr(p->as);
251                 rf = p->from.reg;
252                 rt = p->to.reg;
253                 if(p->from3.type == D_REG){
254                         r = p->from3.reg;
255                         ra = p->reg;
256                         if(ra == NREG)
257                                 ra = REGZERO;
258                 }else{
259                         r = p->reg;
260                         if(r == NREG)
261                                 r = rt;
262                         ra = REGZERO;
263                 }
264                 o1 |= (rf<<16) | (ra<<10) | (r<<5) | rt;
265                 break;
266
267         case 16:        /* XremY R[,R],R -> XdivY; XmsubY */
268                 o1 = oprrr(p->as);
269                 rf = p->from.reg;
270                 rt = p->to.reg;
271                 r = p->reg;
272                 if(r == NREG)
273                         r = rt;
274                 o1 |= (rf<<16) | (r<<5) | REGTMP;
275                 o2 = oprrr(AMSUBW);
276                 o2 |= o1 & (1<<31);     /* same size */
277                 o2 |= (rf<<16) | (r<<10) | (REGTMP<<5) | rt;
278                 break;
279
280         case 17:                /* op Rm,[Rn],Rd; default Rn=ZR */
281                 o1 = oprrr(p->as);
282                 rf = p->from.reg;
283                 rt = p->to.reg;
284                 r = p->reg;
285                 if(p->to.type == D_NONE)
286                         rt = REGZERO;
287                 if(r == NREG)
288                         r = REGZERO;
289                 o1 |= (rf<<16) | (r<<5) | rt;
290                 break;
291
292         case 18:        /* csel cond,Rn,Rm,Rd; cinc/cinv/cneg cond,Rn,Rd; cset cond,Rd */
293                 o1 = oprrr(p->as);
294                 cond = p->from.reg;
295                 r = p->reg;
296                 if(r != NREG){
297                         if(p->from3.type == D_NONE){
298                                 /* CINC/CINV/CNEG */
299                                 rf = r;
300                                 cond ^= 1;
301                         }else
302                                 rf = p->from3.reg;      /* CSEL */
303                 }else{
304                         /* CSET */
305                         if(p->from3.type != D_NONE)
306                                 diag("invalid combination\n%P", p);
307                         r = rf = REGZERO;
308                         cond ^= 1;
309                 }
310                 rt = p->to.reg;
311                 o1 |= (r<<16) | (cond<<12) | (rf<<5) | rt;
312                 break;
313
314         case 19:        /* CCMN cond, (Rm|uimm5),Rn, uimm4 -> ccmn Rn,Rm,uimm4,cond */
315                 nzcv = p->to.offset;
316                 cond = p->from.reg;
317                 if(p->from3.type == D_REG){
318                         o1 = oprrr(p->as);
319                         rf = p->from3.reg;      /* Rm */
320                 }else{
321                         o1 = opirr(p->as);
322                         rf = p->from3.offset & 0x1F;
323                 }
324                 o1 |= (rf<<16) | (cond<<12) | (p->reg<<5) | nzcv;
325                 break;
326
327         case 20:        /* movT R,O(R) -> strT */
328                 v = regoff(&p->to);
329                 r = p->to.reg;
330                 if(r == NREG)
331                         r = o->param;
332                 if(v < 0){      /* unscaled 9-bit signed */
333                         o1 = olsr9s(opstr9(p->as), v, r, p->from.reg);
334                 }else{
335                         v = offsetshift(v, o->a3);
336                         o1 = olsr12u(opstr12(p->as), v, r, p->from.reg);
337                 }
338                 break;
339
340         case 21:        /* movT O(R),R -> ldrT */
341                 v = regoff(&p->from);
342                 r = p->from.reg;
343                 if(r == NREG)
344                         r = o->param;
345                 if(v < 0){      /* unscaled 9-bit signed */
346                         o1 = olsr9s(opldr9(p->as), v, r, p->to.reg);
347                 }else{
348                         v = offsetshift(v, o->a1);
349                         //print("offset=%lld v=%ld a1=%d\n", instoffset, v, o->a1);
350                         o1 = olsr12u(opldr12(p->as), v, r, p->to.reg);
351                 }
352                 break;
353
354         case 22:        /* movT (R)O!,R; movT O(R)!, R -> ldrT */
355                 v = p->from.offset;
356                 if(v < -256 || v > 255)
357                         diag("offset out of range\n%P", p);
358                 o1 = opldrpp(p->as);
359                 if(p->from.type == D_XPOST)
360                         o1 |= 1<<10;
361                 else
362                         o1 |= 3<<10;
363                 o1 |= ((v&0x1FF)<<12) | (p->from.reg<<5) | p->to.reg;
364                 break;
365
366         case 23:        /* movT R,(R)O!; movT O(R)!, R -> strT */
367                 v = p->to.offset;
368                 if(v < -256 || v > 255)
369                         diag("offset out of range\n%P", p);
370                 o1 = LD2STR(opldrpp(p->as));
371                 if(p->to.type == D_XPOST)
372                         o1 |= 1<<10;
373                 else
374                         o1 |= 3<<10;
375                 o1 |= ((v&0x1FF)<<12) | (p->to.reg<<5) | p->from.reg;
376                 break;
377
378         case 24:                /* mov/mvn Rs,Rd -> add $0,Rs,Rd or orr Rs,ZR,Rd */
379                 rf = p->from.reg;
380                 rt = p->to.reg;
381                 s = rf == REGSP || rt == REGSP;
382                 if(p->as == AMVN || p->as == AMVNW){
383                         if(s)
384                                 diag("illegal SP reference\n%P", p);
385                         o1 = oprrr(p->as);
386                         o1 |= (rf<<16) | (REGZERO<<5) | rt;
387                 }else if(s){
388                         o1 = opirr(p->as);
389                         o1 |= (rf<<5) | rt;
390                 }else{
391                         o1 = oprrr(p->as);
392                         o1 |= (rf<<16) | (REGZERO<<5) | rt;
393                 }
394                 break;
395
396         case 25: /* negX Rs, Rd -> subX Rs<<0, ZR, Rd */
397                 o1 = oprrr(p->as);
398                 rf = p->from.reg;
399                 rt = p->to.reg;
400                 o1 |= (rf<<16) | (REGZERO<<5) | rt;
401                 break;
402
403         case 26: /* negX Rm<<s, Rd -> subX Rm<<s, ZR, Rd */
404                 o1 = oprrr(p->as);
405                 o1 |= p->from.offset;   /* includes reg, op, etc */
406                 rt = p->to.reg;
407                 o1 |= (REGZERO<<5) | rt;
408                 break;
409
410         case 27:                /* op Rm<<n[,Rn],Rd (extended register) */
411                 o1 = opxrrr(p->as);
412                 if(p->from.type == D_EXTREG)
413                         o1 |= p->from.offset;   /* includes reg, op, etc */
414                 else
415                         o1 |= p->from.reg << 16;
416                 rt = p->to.reg;
417                 if(p->to.type == D_NONE)
418                         rt = REGZERO;
419                 r = p->reg;
420                 if(r == NREG)
421                         r = rt;
422                 o1 |= (r<<5) | rt;
423                 break;
424
425         case 28:        /* logop $lcon, [R], R (64 bit literal) */
426                 o1 = omovlit(AMOV, p, &p->from, REGTMP);
427                 r = p->reg;
428                 if(r == NREG)
429                         r = p->to.reg;
430                 o2 = oprrr(p->as);
431                 o2 |= REGTMP << 16;     /* shift is 0 */
432                 o2 |= r << 5;
433                 o2 |= p->to.reg;
434                 break;
435
436         case 29:        /* op Rn, Rd */
437                 o1 = oprrr(p->as);
438                 o1 |= p->from.reg<<5 | p->to.reg;
439                 break;
440
441         case 30:        /* movT R,L(R) -> strT */
442                 s = movesize(o->as);
443                 if(s < 0)
444                         diag("unexpected long move, op %A tab %A\n%P", p->as, o->as, p);
445                 v = regoff(&p->to);
446                 if((v & ((1<<s)-1)) != 0)
447                         diag("misaligned offset\n%P", p);
448                 if(v < 0 || (v>>s) >= (1<<24))
449                         goto Hugestxr;
450                 hi = v - (v & (0xFFF<<s));
451                 if((hi & 0xFFF) != 0)
452                         diag("internal: miscalculated offset %ld [%d]\n%P", v, s, p);
453                 //fprint(2, "v=%ld (%#lux) s=%d hi=%ld (%#lux) v'=%ld (%#lux)\n", v, v, s, hi, hi, ((v-hi)>>s)&0xFFF, ((v-hi)>>s)&0xFFF);
454                 r = p->to.reg;
455                 if(r == NREG)
456                         r = o->param;
457                 o1 = oaddi(opirr(AADD), hi, r, REGTMP);
458                 o2 = olsr12u(opstr12(p->as), ((v-hi)>>s)&0xFFF, REGTMP, p->from.reg);
459                 break;
460
461         case 31:        /* movT L(R), R -> ldrT */
462                 s = movesize(o->as);
463                 if(s < 0)
464                         diag("unexpected long move, op %A tab %A\n%P", p->as, o->as, p);
465                 v = regoff(&p->from);
466                 if((v & ((1<<s)-1)) != 0)
467                         diag("misaligned offset\n%P", p);
468                 if(v < 0 || (v>>s) >= (1<<24))
469                         goto Hugeldxr;
470                 hi = v - (v & (0xFFF<<s));
471                 if((hi & 0xFFF) != 0)
472                         diag("internal: miscalculated offset %ld [%d]\n%P", v, s, p);
473                 //fprint(2, "v=%ld (%#lux) s=%d hi=%ld (%#lux) v'=%ld (%#lux)\n", v, v, s, hi, hi, ((v-hi)>>s)&0xFFF, ((v-hi)>>s)&0xFFF);
474                 r = p->from.reg;
475                 if(r == NREG)
476                         r = o->param;
477                 o1 = oaddi(opirr(AADD), hi, r, REGTMP);
478                 o2 = olsr12u(opldr12(p->as), ((v-hi)>>s)&0xFFF, REGTMP, p->to.reg);
479                 break;
480
481         case 32:        /* mov $con, R -> movz/movn */
482                 r = 32;
483                 if(p->as == AMOV)
484                         r = 64;
485                 d = p->from.offset;
486                 s = movcon(d);
487                 if(s < 0 || s >= r){
488                         d = ~d;
489                         s = movcon(d);
490                         if(s < 0 || s >= r)
491                                 diag("impossible move wide: %#llux\n%P", p->from.offset, p);
492                         if(p->as == AMOV)
493                                 o1 = opirr(AMOVN);
494                         else
495                                 o1 = opirr(AMOVNW);
496                 }else{
497                         if(p->as == AMOV)
498                                 o1 = opirr(AMOVZ);
499                         else
500                                 o1 = opirr(AMOVZW);
501                 }
502                 rt = p->to.reg;
503                 o1 |= (((d>>(s*16))& 0xFFFF) << 5) | ((s&3)<<21) | rt;
504                 break;
505
506         case 33:        /* movk $uimm16 << pos */
507                 o1 = opirr(p->as);
508                 d = p->from.offset;
509                 if((d>>16) != 0)
510                         diag("requires uimm16\n%P", p);
511                 s = 0;
512                 if(p->from3.type != D_NONE){
513                         if(p->from3.type != D_CONST)
514                                 diag("missing bit position\n%P", p);
515                         s = p->from3.offset;
516                         if((s&0xF) != 0 || (s /= 16) >= 4 || (o1&S64) == 0 && s >= 2)
517                                 diag("illegal bit position\n%P", p);
518                 }
519                 rt = p->to.reg;
520                 o1 |= ((d & 0xFFFF) << 5) | ((s&3)<<21) | rt;
521                 break;
522                 
523         case 34:        /* mov $lacon,R */
524                 o1 = omovlit(AMOV, p, &p->from, REGTMP);
525                 if(!o1)
526                         break;
527
528                 o2 = opxrrr(AADD);
529                 o2 |= REGTMP << 16;
530                 o2 |= LSL0_64;
531                 r = p->from.reg;
532                 if(r == NREG)
533                         r = o->param;
534                 o2 |= r << 5;
535                 o2 |= p->to.reg;
536                 break;
537
538         case 35:        /* mov SPR,R -> mrs */
539                 o1 = oprrr(AMRS);
540                 v = p->from.offset;
541                 if((o1 & (v & ~(3<<19))) != 0)
542                         diag("MRS register value overlap\n%P", p);
543                 o1 |= v;
544                 o1 |= p->to.reg;
545                 break;
546
547         case 36:        /* mov R,SPR */
548                 o1 = oprrr(AMSR);
549                 v = p->to.offset;
550                 if((o1 & (v & ~(3<<19))) != 0)
551                         diag("MSR register value overlap\n%P", p);
552                 o1 |= v;
553                 o1 |= p->from.reg;
554                 break;
555
556         case 37:        /* mov $con,PSTATEfield -> MSR [immediate] */
557                 if((p->from.offset&~(uvlong)0xF) != 0)
558                         diag("illegal immediate for PSTATE field\n%P", p);
559                 o1 = opirr(AMSR);
560                 o1 |= (p->from.offset&0xF) << 8;        /* Crm */
561                 v = 0;
562                 for(i = 0; i < nelem(pstatefield); i++)
563                         if(pstatefield[i].a == p->to.offset){
564                                 v = pstatefield[i].b;
565                                 break;
566                         }
567                 if(v == 0)
568                         diag("illegal PSTATE field for immediate move\n%P", p);
569                 o1 |= v;
570                 break;
571
572         case 38:        /* clrex [$imm] */
573                 o1 = opimm(p->as);
574                 if(p->to.type == D_NONE)
575                         o1 |= 0xF<<8;
576                 else
577                         o1 |= (p->to.offset & 0xF)<<8;
578                 break;
579
580         case 39:        /* cbz R, rel */
581                 o1 = opirr(p->as);
582                 o1 |= p->from.reg;
583                 o1 |= brdist(p, 0, 19, 2) << 5;
584                 break;
585
586         case 40:        /* tbz */
587                 o1 = opirr(p->as);
588                 v = p->from.offset;
589                 if(v < 0 || v > 63)
590                         diag("illegal bit number\n%P", p);
591                 o1 |= ((v&0x20)<<(31-5)) | ((v&0x1F)<<19);
592                 o1 |= brdist(p, 0, 14, 2)<<5;
593                 o1 |= p->reg;
594                 break;
595
596         case 41:        /* eret, nop, others with no operands */
597                 o1 = op0(p->as);
598                 break;
599
600         case 42:        /* bfm R,r,s,R */
601                 o1 = opbfm(p->as, p->from.offset, p->from3.offset, p->reg, p->to.reg);
602                 break;
603
604         case 43:        /* bfm aliases */
605                 r = p->from.offset;
606                 s = p->from3.offset;
607                 rf = p->reg;
608                 rt = p->to.reg;
609                 if(rf == NREG)
610                         rf = rt;
611                 switch(p->as){
612                 case ABFI:              o1 = opbfm(ABFM, 64-r, s-1, rf, rt); break;
613                 case ABFIW:     o1 = opbfm(ABFMW, 32-r, s-1, rf, rt); break;
614                 case ABFXIL:    o1 = opbfm(ABFM, r, r+s-1, rf, rt); break;
615                 case ABFXILW:   o1 = opbfm(ABFMW, r, r+s-1, rf, rt); break;
616                 case ASBFIZ:    o1 = opbfm(ASBFM, 64-r, s-1, rf, rt); break;
617                 case ASBFIZW:   o1 = opbfm(ASBFMW, 32-r, s-1, rf, rt); break;
618                 case ASBFX:     o1 = opbfm(ASBFM, r, r+s-1, rf, rt); break;
619                 case ASBFXW:    o1 = opbfm(ASBFMW, r, r+s-1, rf, rt); break;
620                 case AUBFIZ:    o1 = opbfm(AUBFM, 64-r, s-1, rf, rt); break;
621                 case AUBFIZW:   o1 = opbfm(AUBFMW, 32-r, s-1, rf, rt); break;
622                 case AUBFX:     o1 = opbfm(AUBFM, r, r+s-1, rf, rt); break;
623                 case AUBFXW:    o1 = opbfm(AUBFMW, r, r+s-1, rf, rt); break;
624                 default:
625                         diag("bad bfm alias\n%P", curp);
626                         break;
627                 }
628                 break;
629
630         case 44:        /* extr $b, Rn, Rm, Rd */
631                 o1 = opextr(p->as, p->from.offset, p->from3.reg, p->reg, p->to.reg);
632                 break;
633
634         case 45:        /* sxt/uxt[bhw] R,R; movT R,R -> sxtT R,R */
635                 rf = p->from.reg;
636                 rt = p->to.reg;
637                 as = p->as;
638                 if(rf == REGZERO)
639                         as = AMOVWU;    /* clearer in disassembly */
640                 switch(as){
641                 case AMOVB:
642                 case ASXTB:     o1 = opbfm(ASBFM, 0, 7, rf, rt); break;
643                 case AMOVH:
644                 case ASXTH:     o1 = opbfm(ASBFM, 0, 15, rf, rt); break;
645                 case AMOVW:
646                 case ASXTW:     o1 = opbfm(ASBFM, 0, 31, rf, rt); break;
647                 case AMOVBU:
648                 case AUXTB:     o1 = opbfm(AUBFM, 0, 7, rf, rt); break;
649                 case AMOVHU:
650                 case AUXTH:     o1 = opbfm(AUBFM, 0, 15, rf, rt); break;
651                 case AMOVWU:    o1 = oprrr(as) | (rf<<16) | (REGZERO<<5) | rt; break;
652                 case AUXTW:     o1 = opbfm(AUBFM, 0, 31, rf, rt); break;
653                 case ASXTBW:    o1 = opbfm(ASBFMW, 0, 7, rf, rt); break;
654                 case ASXTHW:    o1 = opbfm(ASBFMW, 0, 15, rf, rt); break;
655                 case AUXTBW:    o1 = opbfm(AUBFMW, 0, 7, rf, rt); break;
656                 case AUXTHW:    o1 = opbfm(AUBFMW, 0, 15, rf, rt); break;
657                 default:        diag("bad sxt %A", as); break;
658                 }
659                 break;
660
661         case 46:        /* cls */
662                 o1 = opbit(p->as);
663                 o1 |= p->from.reg<<5;
664                 o1 |= p->to.reg;
665                 break;
666
667         case 47:        /* movT R,V(R) -> strT (huge offset) */
668         Hugestxr:
669                 o1 = omovlit(AMOV, p, &p->to, REGTMP);
670                 r = p->to.reg;
671                 if(r == NREG)
672                         r = o->param;
673                 o2 = LD2STR(olsxrr(p->as, REGTMP, r, p->from.reg));
674                 o2 |= 7<<13;    // REGTMP.SX
675                 break;
676
677         case 48:        /* movT V(R), R -> ldrT (huge offset) */
678         Hugeldxr:
679                 o1 = omovlit(AMOV, p, &p->from, REGTMP);
680                 r = p->from.reg;
681                 if(r == NREG)
682                         r = o->param;
683                 o2 = olsxrr(p->as, REGTMP, r, p->to.reg);
684                 o2 |= 7<<13;    // REGTMP.SX
685                 break;
686
687         case 50:        /* sys/sysl */
688                 o1 = opirr(p->as);
689                 if((p->from.offset & ~SYSARG4(0x7, 0xF, 0xF, 0x7)) != 0)
690                         diag("illegal SYS argument\n%P", p);
691                 o1 |= p->from.offset;
692                 if(p->to.type == D_REG)
693                         o1 |= p->to.reg;
694                 else if(p->reg != NREG)
695                         o1 |= p->reg;
696                 else
697                         o1 |= 0x1F;
698                 break;
699
700         case 51:        /* dmb */
701                 o1 = opirr(p->as);
702                 if(p->from.type == D_CONST)
703                         o1 |= (p->from.offset&0xF)<<8;
704                 break;
705
706         case 52:        /* hint */
707                 o1 = opirr(p->as);
708                 o1 |= (p->from.offset&0x7F)<<5;
709                 break;
710
711         case 53:        /* and/or/eor... $bimmN, Rn, Rd -> op (N,r,s), Rn, Rd */
712                 as = p->as;
713                 rt = p->to.reg;
714                 r = p->reg;
715                 if(r == NREG)
716                         r = rt;
717                 if(as == AMOV){
718                         as = AORR;
719                         r = REGZERO;
720                 }else if(as == AMOVW || as == AMOVWU){
721                         as = AORRW;
722                         r = REGZERO;
723                 }
724                 o1 = opirr(as);
725                 mask = findmask(p->from.offset);
726                 if(mask == nil)
727                         mask = findmask(p->from.offset | p->from.offset<<32);
728                 if(mask == nil)
729                         diag("invalid mask %#llux\n%P", p->from.offset, p);
730                 switch(mask->e){
731                 case  2: o1 |= 0xF000; break;
732                 case  4: o1 |= 0xE000; break;
733                 case  8: o1 |= 0xC000; break;
734                 case 16: o1 |= 0x8000; break;
735                 case 64: o1 |= ((o1&S64)!=0)<<22; break;
736                 }
737                 o1 |= (mask->r<<16) | ((mask->s-1)<<10);
738                 o1 |= (r<<5) | rt;
739                 break;
740
741         case 54:        /* floating point arith */
742                 o1 = oprrr(p->as);
743                 if(p->from.type == D_FCONST) {
744                         rf = chipfloat(p->from.ieee);
745                         if(rf < 0 || 1){
746                                 diag("invalid floating-point immediate\n%P", p);
747                                 rf = 0;
748                         }
749                         rf |= (1<<3);
750                 } else
751                         rf = p->from.reg;
752                 rt = p->to.reg;
753                 r = p->reg;
754                 if((o1 & (0x1F<<24)) == (0x1E<<24) && (o1 & (1<<11)) == 0){     /* monadic */
755                         r = rf;
756                         rf = 0;
757                 }else if(r == NREG)
758                         r = rt;
759                 o1 |= (rf << 16) | (r<<5) | rt;
760                 break;
761
762         case 56:        /* floating point compare */
763                 o1 = oprrr(p->as);
764                 if(p->from.type == D_FCONST) {
765                         if(p->from.ieee->h != 0 || p->from.ieee->l != 0)
766                                 diag("invalid floating-point immediate\n%P", p);
767                         o1 |= 8;        /* zero */
768                         rf = 0;
769                 }else
770                         rf = p->from.reg;
771                 rt = p->reg;
772                 o1 |= rf<<16  | rt<<5;
773                 break;
774
775         case 57:        /* floating point conditional compare */
776                 o1 = oprrr(p->as);
777                 cond = p->from.reg;
778                 nzcv = p->to.offset;
779                 if(nzcv & ~0xF)
780                         diag("implausible condition\n%P", p);
781                 rf = p->reg;
782                 if(p->from3.type != D_FREG)
783                         diag("illegal FCCMP\n%P", p);
784                 rt = p->from3.reg;
785                 o1 |= rf<<16 | cond<<12  | rt<<5 | nzcv;
786                 break;
787
788         case 58:        /* ldxr */
789                 o1 = opload(p->as);
790                 o1 |= 0x1F<<16;
791                 o1 |= p->from.reg<<5;
792                 if(p->reg != NREG)
793                         o1 |= p->reg<<10;
794                 else
795                         o1 |= 0x1F<<10;
796                 o1 |= p->to.reg;
797                 break;
798
799         case 59:        /* stxr */
800                 o1 = opstore(p->as);
801                 o1 |= p->reg << 16;
802                 if(p->from3.type != D_NONE)
803                         o1 |= p->from3.reg<<10;
804                 else
805                         o1 |= 0x1F<<10;
806                 o1 |= p->to.reg<<5;
807                 o1 |= p->from.reg;
808                 break;
809
810         case 60:        /* adrp label,r */
811                 d = brdist(p, 12, 21, 0);
812                 o1 = ADR(1, d, p->to.reg);
813                 break;
814
815         case 61:        /* adr label, r */
816                 d = brdist(p, 0, 21, 0);
817                 o1 = ADR(0, d, p->to.reg);
818                 break;
819
820         case 62:        /* case Rv, Rt -> adr tab, Rt; movw Rt[R<<2], Rl; add Rt, Rl; br (Rl) */
821                 o1 = ADR(0, 4*4, p->to.reg);    /* adr 4(pc), Rt */
822                 o2 = (2<<30)|(7<<27)|(2<<22)|(1<<21)|(3<<13)|(1<<12)|(2<<10)|(p->from.reg<<16)|(p->to.reg<<5)|REGTMP;   /* movw Rt[Rv<<2], REGTMP */
823                 o3 = oprrr(AADD) | (p->to.reg<<16) | (REGTMP<<5) | REGTMP;      /* add Rt, REGTMP */
824                 o4 = (0x6b<<25)|(0x1F<<16)|(REGTMP<<5); /* br (REGTMP) */
825                 lastcase = p;
826                 break;
827
828         case 63:        /* bcase */
829                 if(lastcase == nil){
830                         diag("missing CASE\n%P", p);
831                         break;
832                 }
833                 if(p->cond != P) {
834                         o1 = p->cond->pc - (lastcase->pc + 4*4);
835                         if(dlm)
836                                 dynreloc(S, p->pc, 1);
837                 }
838                 break;
839
840         /* reloc ops */
841         case 64:        /* movT R,addr */
842                 o1 = omovlit(AMOV, p, &p->to, REGTMP);
843                 o2 = olsr12u(opstr12(p->as), 0, REGTMP, p->from.reg);
844                 break;
845
846         case 65:        /* movT addr,R */
847                 o1 = omovlit(AMOV, p, &p->from, REGTMP);
848                 o2 = olsr12u(opldr12(p->as), 0, REGTMP, p->to.reg);
849                 break;
850
851         case 66:        /* movpT (R)O!,R; movpT O(R)!, R -> ldrT */
852                 o1 = opldrpp(p->as);
853                 v = p->from.offset >> 2 + ((o1 & S64) != 0);
854                 if(v < -128 || v > 127)
855                         diag("offset out of range\n%P", p);
856                 if(p->from.type == D_XPOST)
857                         o1 |= 1<<23;
858                 else if(p->from.type == D_XPRE)
859                         o1 |= 3<<23;
860                 else
861                         o1 |= 2<<23;
862                 o1 |= ((v&0x7F)<<15) | (p->from.reg<<5) | p->reg | (p->to.reg<<10);
863                 break;
864
865         case 67:        /* movpT R,(R)O!; movpT O(R)!, R -> strT */
866                 o1 = LD2STR(opldrpp(p->as));
867                 v = p->to.offset >> 2 + ((o1 & S64) != 0);
868                 if(v < -128 || v > 127)
869                         diag("offset out of range\n%P", p);
870                 if(p->to.type == D_XPOST)
871                         o1 |= 1<<23;
872                 else if(p->to.type == D_XPRE)
873                         o1 |= 3<<23;
874                 else
875                         o1 |= 2<<23;
876                 o1 |= ((v&0x7F)<<15) | (p->to.reg<<5) | p->from.reg | (p->reg<<10);
877                 break;
878         }
879
880         if(debug['a'] > 1)
881                 Bprint(&bso, "%2d ", o->type);
882
883         v = p->pc;
884         switch(o->size) {
885         default:
886                 if(debug['a'])
887                         Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
888                 break;
889         case 4:
890                 if(debug['a'])
891                         Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
892                 lputl(o1);
893                 break;
894         case 8:
895                 if(debug['a'])
896                         Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
897                 lputl(o1);
898                 lputl(o2);
899                 break;
900         case 12:
901                 if(debug['a'])
902                         Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
903                 lputl(o1);
904                 lputl(o2);
905                 lputl(o3);
906                 break;
907         case 16:
908                 if(debug['a'])
909                         Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
910                                 v, o1, o2, o3, o4, p);
911                 lputl(o1);
912                 lputl(o2);
913                 lputl(o3);
914                 lputl(o4);
915                 break;
916         case 20:
917                 if(debug['a'])
918                         Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
919                                 v, o1, o2, o3, o4, o5, p);
920                 lputl(o1);
921                 lputl(o2);
922                 lputl(o3);
923                 lputl(o4);
924                 lputl(o5);
925                 break;
926         }
927 }
928
929 /*
930  * basic Rm op Rn -> Rd (using shifted register with 0)
931  * also op Rn -> Rt
932  * also Rm*Rn op Ra -> Rd
933  */
934 static long
935 oprrr(int a)
936 {
937         switch(a) {
938         case AADC:      return S64 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10;
939         case AADCW:     return S32 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10;
940         case AADCS:     return S64 | 0<<30 | 1<<29 | 0xd0<<21 | 0<<10;
941         case AADCSW:    return S32 | 0<<30 | 1<<29 | 0xd0<<21 | 0<<10;
942
943         case ANGC:
944         case ASBC:      return S64 | 1<<30 | 0<<29 | 0xd0<<21 | 0<<10;
945         case ANGCS:
946         case ASBCS:     return S64 | 1<<30 | 1<<29 | 0xd0<<21 | 0<<10;
947         case ANGCW:
948         case ASBCW:     return S32 | 1<<30 | 0<<29 | 0xd0<<21 | 0<<10;
949         case ANGCSW:
950         case ASBCSW:    return S32 | 1<<30 | 1<<29 | 0xd0<<21 | 0<<10;
951
952         case AADD:      return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10;
953         case AADDW:     return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10;
954         case ACMN:
955         case AADDS:     return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10;
956         case ACMNW:
957         case AADDSW:    return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10;
958
959         case ASUB:      return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10;
960         case ASUBW:     return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10;
961         case ACMP:
962         case ASUBS:     return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10;
963         case ACMPW:
964         case ASUBSW:    return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10;
965
966         case AAND:      return S64 | 0<<29 | 0xA<<24;
967         case AANDW:     return S32 | 0<<29 | 0xA<<24;
968         case AMOV:
969         case AORR:      return S64 | 1<<29 | 0xA<<24;
970 //      case AMOVW:
971         case AMOVWU:
972         case AORRW:     return S32 | 1<<29 | 0xA<<24;
973         case AEOR:      return S64 | 2<<29 | 0xA<<24;
974         case AEORW:     return S32 | 2<<29 | 0xA<<24;
975         case AANDS:     return S64 | 3<<29 | 0xA<<24;
976         case AANDSW:    return S32 | 3<<29 | 0xA<<24;
977
978         case ABIC:      return S64 | 0<<29 | 0xA<<24 | 1<<21;
979         case ABICW:     return S32 | 0<<29 | 0xA<<24 | 1<<21;
980         case ABICS:     return S64 | 3<<29 | 0xA<<24 | 1<<21;
981         case ABICSW:    return S32 | 3<<29 | 0xA<<24 | 1<<21;
982         case AEON:      return S64 | 2<<29 | 0xA<<24 | 1<<21;
983         case AEONW:     return S32 | 2<<29 | 0xA<<24 | 1<<21;
984         case AMVN:
985         case AORN:      return S64 | 1<<29 | 0xA<<24 | 1<<21;
986         case AMVNW:
987         case AORNW:     return S32 | 1<<29 | 0xA<<24 | 1<<21;
988
989         case AASR:      return S64 | OPDP2(10); /* also ASRV */
990         case AASRW:     return S32 | OPDP2(10);
991         case ALSL:      return S64 | OPDP2(8);
992         case ALSLW:     return S32 | OPDP2(8);
993         case ALSR:      return S64 | OPDP2(9);
994         case ALSRW:     return S32 | OPDP2(9);
995         case AROR:      return S64 | OPDP2(11);
996         case ARORW:     return S32 | OPDP2(11);
997
998         case ACCMN:     return S64 | 0<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4;   /* cond<<12 | nzcv<<0 */
999         case ACCMNW:    return S32 | 0<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4;
1000         case ACCMP:     return S64 | 1<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4;   /* imm5<<16 | cond<<12 | nzcv<<0 */
1001         case ACCMPW:    return S32 | 1<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4;
1002
1003         case ACRC32B:           return S32 | OPDP2(16);
1004         case ACRC32H:           return S32 | OPDP2(17);
1005         case ACRC32W:   return S32 | OPDP2(18);
1006         case ACRC32X:           return S64 | OPDP2(19);
1007         case ACRC32CB:  return S32 | OPDP2(20);
1008         case ACRC32CH:  return S32 | OPDP2(21);
1009         case ACRC32CW:  return S32 | OPDP2(22);
1010         case ACRC32CX:  return S64 | OPDP2(23);
1011
1012         case ACSEL:     return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10;
1013         case ACSELW:    return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10;
1014         case ACSET:     return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10;
1015         case ACSETW:    return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10;
1016         case ACSETM:    return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10;
1017         case ACSETMW:   return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10;
1018         case ACINC:
1019         case ACSINC:    return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10;
1020         case ACINCW:
1021         case ACSINCW:   return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10;
1022         case ACINV:
1023         case ACSINV:    return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10;
1024         case ACINVW:
1025         case ACSINVW:   return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10;
1026         case ACNEG:
1027         case ACSNEG:    return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10;
1028         case ACNEGW:
1029         case ACSNEGW:   return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10;
1030
1031         case AMUL:
1032         case AMADD:     return S64 | 0<<29 | 0x1B<<24 | 0<<21 | 0<<15;
1033         case AMULW:
1034         case AMADDW:    return S32 | 0<<29 | 0x1B<<24 | 0<<21 | 0<<15;
1035         case AMNEG:
1036         case AMSUB:     return S64 | 0<<29 | 0x1B<<24 | 0<<21 | 1<<15;
1037         case AMNEGW:
1038         case AMSUBW:    return S32 | 0<<29 | 0x1B<<24 | 0<<21 | 1<<15;
1039
1040         case AMRS:      return SYSOP(1,2,0,0,0,0,0);
1041         case AMSR:      return SYSOP(0,2,0,0,0,0,0);
1042
1043         case ANEG:      return S64 | 1<<30 | 0<<29 | 0xB<<24 | 0<<21;
1044         case ANEGW:     return S32 | 1<<30 | 0<<29 | 0xB<<24 | 0<<21;
1045         case ANEGS:     return S64 | 1<<30 | 1<<29 | 0xB<<24 | 0<<21;
1046         case ANEGSW:    return S32 | 1<<30 | 1<<29 | 0xB<<24 | 0<<21;
1047
1048         case AREM:
1049         case ASDIV:     return S64 | OPDP2(3);
1050         case AREMW:
1051         case ASDIVW:    return S32 | OPDP2(3);
1052
1053         case ASMULL:
1054         case ASMADDL:   return OPDP3(1, 0, 1, 0);
1055         case ASMNEGL:
1056         case ASMSUBL:   return OPDP3(1, 0, 1, 1);
1057         case ASMULH:    return OPDP3(1, 0, 2, 0);
1058         case AUMULL:
1059         case AUMADDL:   return OPDP3(1, 0, 5, 0);
1060         case AUMNEGL:
1061         case AUMSUBL:   return OPDP3(1, 0, 5, 1);
1062         case AUMULH:    return OPDP3(1, 0, 6, 0);
1063
1064         case AUREM:
1065         case AUDIV:     return S64 | OPDP2(2);
1066         case AUREMW:
1067         case AUDIVW:    return S32 | OPDP2(2);
1068
1069         case AAESE:     return 0x4E<<24 | 2<<20 | 8<<16 | 4<<12 | 2<<10;
1070         case AAESD:     return 0x4E<<24 | 2<<20 | 8<<16 | 5<<12 | 2<<10;
1071         case AAESMC:    return 0x4E<<24 | 2<<20 | 8<<16 | 6<<12 | 2<<10;
1072         case AAESIMC:   return 0x4E<<24 | 2<<20 | 8<<16 | 7<<12 | 2<<10;
1073
1074         case ASHA1C:    return 0x5E<<24 | 0<<12;
1075         case ASHA1P:    return 0x5E<<24 | 1<<12;
1076         case ASHA1M:    return 0x5E<<24 | 2<<12;
1077         case ASHA1SU0:  return 0x5E<<24 | 3<<12;
1078         case ASHA256H:  return 0x5E<<24 | 4<<12;
1079         case ASHA256H2: return 0x5E<<24 | 5<<12;
1080         case ASHA256SU1:        return 0x5E<<24 | 6<<12;
1081
1082         case ASHA1H:    return 0x5E<<24 | 2<<20 | 8<<16 | 0<<12 | 2<<10;
1083         case ASHA1SU1:  return 0x5E<<24 | 2<<20 | 8<<16 | 1<<12 | 2<<10;
1084         case ASHA256SU0:        return 0x5E<<24 | 2<<20 | 8<<16 | 2<<12 | 2<<10;
1085
1086         case AFCVTZSD:  return FPCVTI(1, 0, 1, 3, 0);
1087         case AFCVTZSDW: return FPCVTI(0, 0, 1, 3, 0);
1088         case AFCVTZSS:  return FPCVTI(1, 0, 0, 3, 0);
1089         case AFCVTZSSW: return FPCVTI(0, 0, 0, 3, 0);
1090
1091         case AFCVTZUD:  return FPCVTI(1, 0, 1, 3, 1);
1092         case AFCVTZUDW: return FPCVTI(0, 0, 1, 3, 1);
1093         case AFCVTZUS:  return FPCVTI(1, 0, 0, 3, 1);
1094         case AFCVTZUSW: return FPCVTI(0, 0, 0, 3, 1);
1095
1096         case ASCVTFD:           return FPCVTI(1, 0, 1, 0, 2);
1097         case ASCVTFS:           return FPCVTI(1, 0, 0, 0, 2);
1098         case ASCVTFWD:  return FPCVTI(0, 0, 1, 0, 2);
1099         case ASCVTFWS:  return FPCVTI(0, 0, 0, 0, 2);
1100
1101         case AUCVTFD:           return FPCVTI(1, 0, 1, 0, 3);
1102         case AUCVTFS:           return FPCVTI(1, 0, 0, 0, 3);
1103         case AUCVTFWD:  return FPCVTI(0, 0, 1, 0, 3);
1104         case AUCVTFWS:  return FPCVTI(0, 0, 0, 0, 3);
1105
1106         case AFADDS:    return FPOP2S(0, 0, 0, 2);
1107         case AFADDD:    return FPOP2S(0, 0, 1, 2);
1108         case AFSUBS:    return FPOP2S(0, 0, 0, 3);
1109         case AFSUBD:    return FPOP2S(0, 0, 1, 3);
1110         case AFMULS:    return FPOP2S(0, 0, 0, 0);
1111         case AFMULD:    return FPOP2S(0, 0, 1, 0);
1112         case AFDIVS:    return FPOP2S(0, 0, 0, 1);
1113         case AFDIVD:    return FPOP2S(0, 0, 1, 1);
1114         case AFMAXS:    return FPOP2S(0, 0, 0, 4);
1115         case AFMINS:    return FPOP2S(0, 0, 0, 5);
1116         case AFMAXD:    return FPOP2S(0, 0, 1, 4);
1117         case AFMIND:    return FPOP2S(0, 0, 1, 5);
1118         case AFMAXNMS:  return FPOP2S(0, 0, 0, 6);
1119         case AFMAXNMD:  return FPOP2S(0, 0, 1, 6);
1120         case AFMINNMS:  return FPOP2S(0, 0, 0, 7);
1121         case AFMINNMD:  return FPOP2S(0, 0, 1, 7);
1122         case AFNMULS:           return FPOP2S(0, 0, 0, 8);
1123         case AFNMULD:   return FPOP2S(0, 0, 1, 8);
1124
1125         case AFCMPS:    return FPCMP(0, 0, 0, 0, 0);
1126         case AFCMPD:    return FPCMP(0, 0, 1, 0, 0);
1127         case AFCMPES:   return FPCMP(0, 0, 0, 0, 16);
1128         case AFCMPED:   return FPCMP(0, 0, 1, 0, 16);
1129
1130         case AFCCMPS:           return FPCCMP(0, 0, 0, 0);
1131         case AFCCMPD:   return FPCCMP(0, 0, 1, 0);
1132         case AFCCMPES:  return FPCCMP(0, 0, 0, 1);
1133         case AFCCMPED:  return FPCCMP(0, 0, 1, 1);
1134
1135         case AFCSELS:   return 0x1E<<24 | 0<<22 | 1<<21 | 3<<10;
1136         case AFCSELD:   return 0x1E<<24 | 1<<22 | 1<<21 | 3<<10;
1137
1138         case AFMOVS:    return FPOP1S(0, 0, 0, 0);
1139         case AFABSS:    return FPOP1S(0, 0, 0, 1);
1140         case AFNEGS:    return FPOP1S(0, 0, 0, 2);
1141         case AFSQRTS:   return FPOP1S(0, 0, 0, 3);
1142         case AFCVTSD:   return FPOP1S(0, 0, 0, 5);
1143         case AFCVTSH:   return FPOP1S(0, 0, 0, 7);
1144         case AFRINTNS: return FPOP1S(0, 0, 0, 8);
1145         case AFRINTPS:  return FPOP1S(0, 0, 0, 9);
1146         case AFRINTMS:  return FPOP1S(0, 0, 0, 10);
1147         case AFRINTZS:  return FPOP1S(0, 0, 0, 11);
1148         case AFRINTAS:  return FPOP1S(0, 0, 0, 12);
1149         case AFRINTXS:  return FPOP1S(0, 0, 0, 14);
1150         case AFRINTIS:  return FPOP1S(0, 0, 0, 15);
1151
1152         case AFMOVD:    return FPOP1S(0, 0, 1, 0);
1153         case AFABSD:    return FPOP1S(0, 0, 1, 1);
1154         case AFNEGD:    return FPOP1S(0, 0, 1, 2);
1155         case AFSQRTD:   return FPOP1S(0, 0, 1, 3);
1156         case AFCVTDS:   return FPOP1S(0, 0, 1, 4);
1157         case AFCVTDH:   return FPOP1S(0, 0, 1, 7);
1158         case AFRINTND:  return FPOP1S(0, 0, 1, 8);
1159         case AFRINTPD:  return FPOP1S(0, 0, 1, 9);
1160         case AFRINTMD:  return FPOP1S(0, 0, 1, 10);
1161         case AFRINTZD:  return FPOP1S(0, 0, 1, 11);
1162         case AFRINTAD:  return FPOP1S(0, 0, 1, 12);
1163         case AFRINTXD:  return FPOP1S(0, 0, 1, 14);
1164         case AFRINTID:  return FPOP1S(0, 0, 1, 15);
1165         case AFCVTHS:   return FPOP1S(0, 0, 3, 4);
1166         case AFCVTHD:   return FPOP1S(0, 0, 3, 5);
1167
1168         }
1169         diag("bad rrr %d %A", a, a);
1170         prasm(curp);
1171         return 0;
1172 }
1173
1174 /*
1175  * imm -> Rd
1176  * imm op Rn -> Rd
1177  */
1178 static long
1179 opirr(int a)
1180 {
1181         switch(a){
1182
1183         /* op $addcon, Rn, Rd */
1184         case AMOV:
1185         case AADD:      return S64 | 0<<30 | 0<<29 | 0x11<<24;
1186         case ACMN:
1187         case AADDS:     return S64 | 0<<30 | 1<<29 | 0x11<<24;
1188         case AMOVW:
1189         case AADDW:     return S32 | 0<<30 | 0<<29 | 0x11<<24;
1190         case ACMNW:
1191         case AADDSW:    return S32 | 0<<30 | 1<<29 | 0x11<<24;
1192         case ASUB:      return S64 | 1<<30 | 0<<29 | 0x11<<24;
1193         case ACMP:
1194         case ASUBS:     return S64 | 1<<30 | 1<<29 | 0x11<<24;
1195         case ASUBW:     return S32 | 1<<30 | 0<<29 | 0x11<<24;
1196         case ACMPW:
1197         case ASUBSW:    return S32 | 1<<30 | 1<<29 | 0x11<<24;
1198
1199         /* op $imm(SB), Rd; op label, Rd */
1200         case AADR:      return 0<<31 | 0x10<<24;
1201         case AADRP:     return 1<<31 | 0x10<<24;
1202
1203         /* op $bimm, Rn, Rd */
1204         case AAND:      return S64 | 0<<29 | 0x24<<23;
1205         case AANDW:     return S32 | 0<<29 | 0x24<<23 | 0<<22;
1206         case AORR:      return S64 | 1<<29 | 0x24<<23;
1207         case AORRW:     return S32 | 1<<29 | 0x24<<23 | 0<<22;
1208         case AEOR:      return S64 | 2<<29 | 0x24<<23;
1209         case AEORW:     return S32 | 2<<29 | 0x24<<23 | 0<<22;
1210         case AANDS:     return S64 | 3<<29 | 0x24<<23;
1211         case AANDSW:    return S32 | 3<<29 | 0x24<<23 | 0<<22;
1212
1213         case AASR:      return S64 | 0<<29 | 0x26<<23;  /* alias of SBFM */
1214         case AASRW:     return S32 | 0<<29 | 0x26<<23 | 0<<22;
1215
1216         /* op $width, $lsb, Rn, Rd */
1217         case ABFI:              return S64 | 2<<29 | 0x26<<23 | 1<<22;  /* alias of BFM */
1218         case ABFIW:     return S32 | 2<<29 | 0x26<<23 | 0<<22;
1219
1220         /* op $imms, $immr, Rn, Rd */
1221         case ABFM:      return S64 | 1<<29 | 0x26<<23 | 1<<22;
1222         case ABFMW:     return S32 | 1<<29 | 0x26<<23 | 0<<22;
1223         case ASBFM:     return S64 | 0<<29 | 0x26<<23 | 1<<22;
1224         case ASBFMW:    return S32 | 0<<29 | 0x26<<23 | 0<<22;
1225         case AUBFM:     return S64 | 2<<29 | 0x26<<23 | 1<<22;
1226         case AUBFMW:    return S32 | 2<<29 | 0x26<<23 | 0<<22;
1227
1228         case ABFXIL:    return S64 | 1<<29 | 0x26<<23 | 1<<22;  /* alias of BFM */
1229         case ABFXILW:   return S32 | 1<<29 | 0x26<<23 | 0<<22;
1230
1231         case AEXTR:     return S64 | 0<<29 | 0x27<<23 | 1<<22 | 0<<21;
1232         case AEXTRW:    return S32 | 0<<29 | 0x27<<23 | 0<<22 | 0<<21;
1233
1234         case ACBNZ:     return S64 | 0x1A<<25 | 1<<24;
1235         case ACBNZW:    return S32 | 0x1A<<25 | 1<<24;
1236         case ACBZ:      return S64 | 0x1A<<25 | 0<<24;
1237         case ACBZW:     return S32 | 0x1A<<25 | 0<<24;
1238
1239         case ACCMN:     return S64 | 0<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4;   /* imm5<<16 | cond<<12 | nzcv<<0 */
1240         case ACCMNW:    return S32 | 0<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4;
1241         case ACCMP:     return S64 | 1<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4;   /* imm5<<16 | cond<<12 | nzcv<<0 */
1242         case ACCMPW:    return S32 | 1<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4;
1243
1244         case AMOVK:     return S64 | 3<<29 | 0x25<<23;
1245         case AMOVKW:    return S32 | 3<<29 | 0x25<<23;
1246
1247         case AMOVN:     return S64 | 0<<29 | 0x25<<23;
1248         case AMOVNW:    return S32 | 0<<29 | 0x25<<23;
1249         case AMOVZ:     return S64 | 2<<29 | 0x25<<23;
1250         case AMOVZW:    return S32 | 2<<29 | 0x25<<23;
1251
1252         case AMSR:      return SYSOP(0,0,0,4,0,0,0x1F); /* MSR (immediate) */
1253
1254         case AAT:
1255         case ADC:
1256         case AIC:
1257         case ATLBI:
1258         case ASYS:      return SYSOP(0,1,0,0,0,0,0);
1259         case ASYSL:     return SYSOP(1,1,0,0,0,0,0);
1260
1261         case ATBZ:      return 0x36<<24;
1262         case ATBNZ:     return 0x37<<24;
1263
1264         case ADSB:      return SYSOP(0,0,3,3,0,4,0x1F);
1265         case ADMB:      return SYSOP(0,0,3,3,0,5,0x1F);
1266         case AISB:      return SYSOP(0,0,3,3,0,6,0x1F);
1267         case AHINT:     return SYSOP(0,0,3,2,0,0,0x1F);
1268
1269         }
1270         diag("bad irr %A", a);
1271         prasm(curp);
1272         return 0;
1273 }
1274
1275 /*
1276  * bit operations
1277  */
1278 #define OPBIT(x)        (1<<30 | 0<<29 | 0xD6<<21 | 0<<16 | (x)<<10)
1279
1280 static long
1281 opbit(int a)
1282 {
1283         switch(a){
1284         case ACLS:      return S64 | OPBIT(5);
1285         case ACLSW:     return S32 | OPBIT(5);
1286         case ACLZ:      return S64 | OPBIT(4);
1287         case ACLZW:     return S32 | OPBIT(4);
1288         case ARBIT:     return S64 | OPBIT(0);
1289         case ARBITW:    return S32 | OPBIT(0);
1290         case AREV:      return S64 | OPBIT(3);
1291         case AREVW:     return S32 | OPBIT(2);
1292         case AREV16:    return S64 | OPBIT(1);
1293         case AREV16W:   return S32 | OPBIT(1);
1294         case AREV32:    return S64 | OPBIT(2);
1295         default:
1296                 diag("bad bit op\n%P", curp);
1297                 return 0;
1298         }
1299 }
1300
1301 /*
1302  * add/subtract extended register
1303  */
1304 static long
1305 opxrrr(int a)
1306 {
1307         switch(a) {
1308         case AADD:      return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64;
1309         case AADDW:     return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32;
1310         case ACMN:
1311         case AADDS:     return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64;
1312         case ACMNW:
1313         case AADDSW:    return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32;
1314
1315         case ASUB:      return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64;
1316         case ASUBW:     return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32;
1317         case ACMP:
1318         case ASUBS:     return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64;
1319         case ACMPW:
1320         case ASUBSW:    return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32;
1321
1322         }
1323         diag("bad opxrrr %A\n%P", a, curp);
1324         return 0;
1325 }
1326
1327 static long
1328 opimm(int a)
1329 {
1330         switch(a){
1331         case ASVC:      return 0xD4<<24 | 0<<21 | 1;    /* imm16<<5 */
1332         case AHVC:      return 0xD4<<24 | 0<<21 | 2;
1333         case ASMC:      return 0xD4<<24 | 0<<21 | 3;
1334         case ABRK:      return 0xD4<<24 | 1<<21 | 0;
1335         case AHLT:      return 0xD4<<24 | 2<<21 | 0;
1336         case ADCPS1:    return 0xD4<<24 | 5<<21 | 1;
1337         case ADCPS2:    return 0xD4<<24 | 5<<21 | 2;
1338         case ADCPS3:    return 0xD4<<24 | 5<<21 | 3;
1339
1340         case ACLREX:    return SYSOP(0,0,3,3,0,2,0x1F);
1341         }
1342         diag("bad imm %A", a);
1343         prasm(curp);
1344         return 0;
1345 }
1346
1347 static vlong
1348 brdist(Prog *p, int preshift, int flen, int shift)
1349 {
1350         vlong v, t;
1351         Sym *s;
1352
1353         v = 0;
1354         if(p->cond == UP) {
1355                 s = p->to.sym;
1356                 if(s->type != SUNDEF)
1357                         diag("bad branch sym type");
1358                 v = (uvlong)s->value >> (Roffset-2);
1359                 dynreloc(s, p->pc, 0);  /* TO DO */
1360         }
1361         else if(p->cond != P)
1362                 v = (p->cond->pc>>preshift) - (pc>>preshift);
1363         if((v & ((1<<shift)-1)) != 0)
1364                 diag("misaligned label\n%P", p);
1365         v >>= shift;
1366         t = (vlong)1 << (flen-1);
1367         if(v < -t || v >= t)
1368                 diag("branch too far\n%P", p);
1369         return v & ((t<<1)-1);
1370 }
1371
1372 /*
1373  * pc-relative branches
1374  */
1375 static long
1376 opbra(int a)
1377 {
1378         switch(a) {
1379         case ABEQ:      return OPBcc(0x0);
1380         case ABNE:      return OPBcc(0x1);
1381         case ABCS:      return OPBcc(0x2);
1382         case ABHS:      return OPBcc(0x2);
1383         case ABCC:      return OPBcc(0x3);
1384         case ABLO:      return OPBcc(0x3);
1385         case ABMI:      return OPBcc(0x4);
1386         case ABPL:      return OPBcc(0x5);
1387         case ABVS:      return OPBcc(0x6);
1388         case ABVC:      return OPBcc(0x7);
1389         case ABHI:      return OPBcc(0x8);
1390         case ABLS:      return OPBcc(0x9);
1391         case ABGE:      return OPBcc(0xa);
1392         case ABLT:      return OPBcc(0xb);
1393         case ABGT:      return OPBcc(0xc);
1394         case ABLE:      return OPBcc(0xd);              /* imm19<<5 | cond */
1395         case AB:                return 0<<31 | 5<<26;   /* imm26 */
1396         case ABL:               return 1<<31 | 5<<26;
1397         }
1398         diag("bad bra %A", a);
1399         prasm(curp);
1400         return 0;
1401 }
1402
1403 static long
1404 opbrr(int a)
1405 {
1406         switch(a){
1407         case ABL:               return OPBLR(1);                /* BLR */
1408         case AB:                return OPBLR(0);                /* BR */
1409         case ARET:      return OPBLR(2);                /* RET */
1410         }
1411         diag("bad brr %A", a);
1412         prasm(curp);
1413         return 0;
1414 }
1415
1416 static long
1417 op0(int a)
1418 {
1419         switch(a){
1420         case ADRPS:     return 0x6B<<25 | 5<<21 | 0x1F<<16 | 0x1F<<5;
1421         case AERET:     return 0x6B<<25 | 4<<21 | 0x1F<<16 | 0<<10 | 0x1F<<5;
1422         case ANOP:      return SYSHINT(0);
1423         case AYIELD:    return SYSHINT(1);
1424         case AWFE:      return SYSHINT(2);
1425         case AWFI:      return SYSHINT(3);
1426         case ASEV:      return SYSHINT(4);
1427         case ASEVL:     return SYSHINT(5);
1428         }
1429         diag("bad op0 %A", a);
1430         prasm(curp);
1431         return 0;
1432 }
1433
1434 /*
1435  * register offset
1436  */
1437 static long
1438 opload(int a)
1439 {
1440         switch(a){
1441         case ALDAR:     return LDSTX(3,1,1,0,1) | 0x1F<<10;
1442         case ALDARW:    return LDSTX(2,1,1,0,1) | 0x1F<<10;
1443         case ALDARB:    return LDSTX(0,1,1,0,1) | 0x1F<<10;
1444         case ALDARH:    return LDSTX(1,1,1,0,1) | 0x1F<<10;
1445         case ALDAXP:    return LDSTX(3,0,1,1,1);
1446         case ALDAXPW:   return LDSTX(2,0,1,1,1);
1447         case ALDAXR:    return LDSTX(3,0,1,0,1) | 0x1F<<10;
1448         case ALDAXRW:   return LDSTX(2,1,1,0,1) | 0x1F<<10;
1449         case ALDAXRB:   return LDSTX(0,0,1,0,1) | 0x1F<<10;
1450         case ALDAXRH:   return LDSTX(1,0,1,0,1) | 0x1F<<10;
1451         case ALDXR:             return LDSTX(3,0,1,0,0) | 0x1F<<10;
1452         case ALDXRB:            return LDSTX(0,0,1,0,0) | 0x1F<<10;
1453         case ALDXRH:            return LDSTX(1,0,1,0,0) | 0x1F<<10;
1454         case ALDXRW:            return LDSTX(2,0,1,0,0) | 0x1F<<10;
1455         case ALDXP:             return LDSTX(3,0,1,1,0);
1456         case ALDXPW:            return LDSTX(2,0,1,1,0);
1457         case AMOVNP:    return S64 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22;
1458         case AMOVNPW:   return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22;
1459         }
1460         diag("bad opload %A\n%P", a, curp);
1461         return 0;
1462 }
1463
1464 static long
1465 opstore(int a)
1466 {
1467         switch(a){
1468         case ASTLR:             return LDSTX(3,1,0,0,1) | 0x1F<<10;
1469         case ASTLRB:            return LDSTX(0,1,0,0,1) | 0x1F<<10;
1470         case ASTLRH:            return LDSTX(1,1,0,0,1) | 0x1F<<10;
1471         case ASTLP:             return LDSTX(3,0,0,1,1);
1472         case ASTLPW:            return LDSTX(2,0,0,1,1);
1473         case ASTLRW:            return LDSTX(2,1,0,0,1) | 0x1F<<10;
1474         case ASTLXP:            return LDSTX(2,0,0,1,1);
1475         case ASTLXPW:           return LDSTX(3,0,0,1,1);
1476         case ASTLXR:            return LDSTX(3,0,0,0,1) | 0x1F<<10;
1477         case ASTLXRB:           return LDSTX(0,0,0,0,1) | 0x1F<<10;
1478         case ASTLXRH:           return LDSTX(1,0,0,0,1) | 0x1F<<10;
1479         case ASTLXRW:           return LDSTX(2,0,0,0,1) | 0x1F<<10;
1480         case ASTXR:             return LDSTX(3,0,0,0,0) | 0x1F<<10;
1481         case ASTXRB:            return LDSTX(0,0,0,0,0) | 0x1F<<10;
1482         case ASTXRH:            return LDSTX(1,0,0,0,0) | 0x1F<<10;
1483         case ASTXP:             return LDSTX(3,0,0,1,0);
1484         case ASTXPW:            return LDSTX(2,0,0,1,0);
1485         case ASTXRW:            return LDSTX(2,0,0,0,0) | 0x1F<<10;
1486         case AMOVNP:    return S64 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22;
1487         case AMOVNPW:   return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22;
1488         }
1489         diag("bad opstore %A\n%P", a, curp);
1490         return 0;
1491 }
1492
1493 /*
1494  * load/store register (unsigned immediate) C3.3.13
1495  *      these produce 64-bit values (when there's an option)
1496  */
1497
1498 static long
1499 olsr12u(long o, long v, int b, int r)
1500 {
1501         if(v < 0 || v >= (1<<12))
1502                 diag("offset out of range: %ld\n%P", v, curp);
1503         o |= (v&0xFFF)<<10;
1504         o |= b << 5;
1505         o |= r;
1506         return o;
1507 }
1508
1509 static long
1510 opldr12(int a)
1511 {
1512         switch(a){
1513         case AMOV:      return LDSTR12U(3, 0, 1);       /* imm12<<10 | Rn<<5 | Rt */
1514         case AMOVW:     return LDSTR12U(2, 0, 2);
1515         case AMOVWU:    return LDSTR12U(2, 0, 1);
1516         case AMOVH:     return LDSTR12U(1, 0, 2);
1517         case AMOVHU:    return LDSTR12U(1, 0, 1);
1518         case AMOVB:     return LDSTR12U(0, 0, 2);
1519         case AMOVBU:    return LDSTR12U(0, 0, 1);
1520         case AFMOVS:    return LDSTR12U(2, 1, 1);
1521         case AFMOVD:    return LDSTR12U(3, 1, 1);
1522         }
1523         diag("bad opldr12 %A\n%P", a, curp);
1524         return 0;
1525 }
1526
1527 static long
1528 opstr12(int a)
1529 {
1530         return LD2STR(opldr12(a));
1531 }
1532
1533 /* 
1534  * load/store register (unscaled immediate) C3.3.12
1535  */
1536
1537 static long
1538 olsr9s(long o, long v, int b, int r)
1539 {
1540         if(v < -256 || v > 255)
1541                 diag("offset out of range: %ld\n%P", v, curp);
1542         o |= (v&0x1FF)<<12;
1543         o |= b << 5;
1544         o |= r;
1545         return o;
1546 }
1547
1548 static long
1549 opldr9(int a)
1550 {
1551         switch(a){
1552         case AMOV:      return LDSTR9S(3, 0, 1);        /* simm9<<12 | Rn<<5 | Rt */
1553         case AMOVW:     return LDSTR9S(2, 0, 2);
1554         case AMOVWU:    return LDSTR9S(2, 0, 1);
1555         case AMOVH:     return LDSTR9S(1, 0, 2);
1556         case AMOVHU:    return LDSTR9S(1, 0, 1);
1557         case AMOVB:     return LDSTR9S(0, 0, 2);
1558         case AMOVBU:    return LDSTR9S(0, 0, 1);
1559         case AFMOVS:    return LDSTR9S(2, 1, 1);
1560         case AFMOVD:    return LDSTR9S(3, 1, 1);
1561         }
1562         diag("bad opldr9 %A\n%P", a, curp);
1563         return 0;
1564 }
1565
1566 static long
1567 opstr9(int a)
1568 {
1569         return LD2STR(opldr9(a));
1570 }
1571
1572 static long
1573 opldrpp(int a)
1574 {
1575         switch(a){
1576         case AMOV:      return 3<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22;   /* simm9<<12 | Rn<<5 | Rt */
1577         case AMOVW:     return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22;
1578         case AMOVWU:    return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22;
1579         case AMOVH:     return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22;
1580         case AMOVHU:    return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22;
1581         case AMOVB:     return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22;
1582         case AMOVBU:    return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22;
1583         case AMOVPW:    return 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22;
1584         case AMOVPSW:   return 1<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22;
1585         case AMOVP:     return 2<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22;
1586         }
1587         diag("bad opldr %A\n%P", a, curp);
1588         return 0;
1589 }
1590
1591 /*
1592  * load/store register (extended register)
1593  */
1594 static long
1595 olsxrr(int a, int b, int c, int d)
1596 {
1597         return opldrpp(a) | 1<<21 | b<<16 | 2<<10 | c<<5 | d;
1598 }
1599
1600 static long
1601 oaddi(long o1, long v, int r, int rt)
1602 {
1603         if((v & 0xFFF000) != 0){
1604                 v >>= 12;
1605                 o1 |= 1<<22;
1606         }
1607         o1 |= ((v & 0xFFF) << 10) | (r<<5) | rt;
1608         return o1;
1609 }
1610
1611 /*
1612  * load a literal value into dr
1613  */
1614 static long
1615 omovlit(int as, Prog *p, Adr *a, int dr)
1616 {       
1617         long v, o1;
1618         int w, fp;
1619
1620         if(p->cond == nil){     /* not in literal pool */
1621                 aclass(a);
1622                 /* TO DO: could be clever, and use general constant builder */
1623                 o1 = opirr(AADD);
1624                 v = instoffset;
1625                 if(v != 0 && (v & 0xFFF) == 0){
1626                         v >>= 12;
1627                         o1 |= 1<<22;    /* shift, by 12 */
1628                 }
1629                 if(v < 0 || v > 0xFFF)
1630                         diag("literal out of range\n%P", p);
1631                 o1 |= ((v& 0xFFF) << 10) | (REGZERO<<5) | dr;
1632         }else{
1633                 fp = 0;
1634                 w = 0;  /* default: 32 bit, unsigned */
1635                 switch(as){
1636                 case AFMOVS:
1637                         fp = 1;
1638                         break;
1639                 case AFMOVD:
1640                         fp = 1;
1641                         w = 1;  /* 64 bit simd&fp */
1642                         break;
1643                 case AMOV:
1644                         if(p->cond->as == ADWORD)
1645                                 w = 1;  /* 64 bit */
1646                         else if(p->cond->to.offset < 0)
1647                                 w = 2;  /* sign extend */
1648                         break;
1649                 case AMOVB:
1650                 case AMOVH:
1651                 case AMOVW:
1652                         w = 2;  /* 32 bit, sign-extended to 64 */
1653                         break;
1654                 }
1655                 v = brdist(p, 0, 19, 2);
1656                 o1 = (w<<30)|(fp<<26)|(3<<27);
1657                 o1 |= (v&0x7FFFF)<<5;
1658                 o1 |= dr;
1659         }
1660         return o1;
1661 }
1662
1663 static long
1664 opbfm(int a, int r, int s, int rf, int rt)
1665 {
1666         long o, c;
1667
1668         o = opirr(a);
1669         if((o & (1<<31)) == 0)
1670                 c = 32;
1671         else
1672                 c = 64;
1673         if(r < 0 || r >= c)
1674                 diag("illegal bit number\n%P", curp);
1675         o |= (r&0x3F)<<16;
1676         if(s < 0 || s >= c)
1677                 diag("illegal bit number\n%P", curp);
1678         o |= (s&0x3F)<<10;
1679         o |= (rf<<5) | rt;
1680         return o;
1681 }
1682
1683 static long
1684 opextr(int a, long v, int rn, int rm, int rt)
1685 {
1686         long o, c;
1687
1688         o = opirr(a);
1689         c = (o & (1<<31)) != 0? 63: 31;
1690         if(v < 0 || v > c)
1691                 diag("illegal bit number\n%P", curp);
1692         o |= v<<10;
1693         o |= rn << 5;
1694         o |= rm << 16;
1695         o |= rt;
1696         return o;
1697 }
1698
1699 /*
1700  * size in log2(bytes)
1701  */
1702 static int
1703 movesize(int a)
1704 {
1705         switch(a){
1706         case AMOV:
1707                 return 3;
1708         case AMOVW:
1709         case AMOVWU:
1710                 return 2;
1711         case AMOVH:
1712         case AMOVHU:
1713                 return 1;
1714         case AMOVB:
1715         case AMOVBU:
1716                 return 0;
1717         case AFMOVS:
1718                 return 2;
1719         case AFMOVD:
1720                 return 3;
1721         default:
1722                 return -1;
1723         }
1724 }
1725
1726 /*
1727  * SIMD
1728  */