%{
#define INTTMP 0x03f0
#define INTVAR 0x0300
#define FLTTMP 0x0e
#define FLTVAR 0xf0

#define savelist	(0xd800) /* fp, ip, lr, pc */
#define reslist		(0xa800) /* fp, sp, pc */

#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))

#define readsreg(p) \
        (generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P)
#define setsrc(d) ((d) && (d)->x.regnode && \
        (d)->x.regnode->set == src->x.regnode->set && \
        (d)->x.regnode->mask&src->x.regnode->mask)

#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b))

#include "c.h"
#define NODEPTR_TYPE Node
#define OP_LABEL(p) ((p)->op)
#define LEFT_CHILD(p) ((p)->kids[0])
#define RIGHT_CHILD(p) ((p)->kids[1])
#define STATE_LABEL(p) ((p)->x.state)
static void address(Symbol, Symbol, int);
static void blkfetch(int, int, int, int);
static void blkloop(int, int, int, int, int, int[]);
static void blkstore(int, int, int, int);
static void defaddress(Symbol);
static void defconst(int, int, Value);
static void defstring(int, char *);
static void defsymbol(Symbol);
static void doarg(Node);
static void emit2(Node);
static void export(Symbol);
static void clobber(Node);
static void function(Symbol, Symbol [], Symbol [], int);
static void global(Symbol);
static void import(Symbol);
static void local(Symbol);
static void progbeg(int, char **);
static void progend(void);
static void segment(int);
static void space(int);
static void target(Node);
static int  imm(Node);
static int  imm_const(unsigned);
static int  bitcount(unsigned);
static void arm_blkcopy(int, int, int, int, int);
static void arm_mov(int, int);
static void arm_add(int, int, int);
static char *reglist(unsigned);

static Symbol ireg[32], freg[32];
static Symbol iregw, fregw;
static int cseg;
static int sizeisave;
static int bigargs;
%}
%start stmt
%term CNSTF4=4113 CNSTF8=8209
%term CNSTI1=1045 CNSTI2=2069 CNSTI4=4117
%term CNSTP4=4119
%term CNSTU1=1046 CNSTU2=2070 CNSTU4=4118
%term ARGB=41
%term ARGF4=4129 ARGF8=8225
%term ARGI4=4133
%term ARGP4=4135
%term ARGU4=4134
%term ASGNB=57
%term ASGNF4=4145 ASGNF8=8241
%term ASGNI1=1077 ASGNI2=2101 ASGNI4=4149
%term ASGNP4=4151
%term ASGNU1=1078 ASGNU2=2102 ASGNU4=4150
%term INDIRB=73
%term INDIRF4=4161 INDIRF8=8257
%term INDIRI1=1093 INDIRI2=2117 INDIRI4=4165
%term INDIRP4=4167
%term INDIRU1=1094 INDIRU2=2118 INDIRU4=4166
%term CVFF4=4209 CVFF8=8305
%term CVFI4=4213
%term CVIF4=4225 CVIF8=8321
%term CVII1=1157 CVII2=2181 CVII4=4229
%term CVIU1=1158 CVIU2=2182 CVIU4=4230
%term CVPU4=4246
%term CVUI1=1205 CVUI2=2229 CVUI4=4277
%term CVUP4=4279
%term CVUU1=1206 CVUU2=2230 CVUU4=4278
%term NEGF4=4289 NEGF8=8385
%term NEGI4=4293
%term CALLB=217
%term CALLF4=4305 CALLF8=8401
%term CALLI4=4309
%term CALLP4=4311
%term CALLU4=4310
%term CALLV=216
%term RETF4=4337 RETF8=8433
%term RETI4=4341
%term RETP4=4343
%term RETU4=4342
%term RETV=248
%term ADDRGP4=4359
%term ADDRFP4=4375
%term ADDRLP4=4391
%term ADDF4=4401 ADDF8=8497
%term ADDI4=4405
%term ADDP4=4407
%term ADDU4=4406
%term SUBF4=4417 SUBF8=8513
%term SUBI4=4421
%term SUBP4=4423
%term SUBU4=4422
%term LSHI4=4437
%term LSHU4=4438
%term MODI4=4453
%term MODU4=4454
%term RSHI4=4469
%term RSHU4=4470
%term BANDI4=4485
%term BANDU4=4486
%term BCOMI4=4501
%term BCOMU4=4502
%term BORI4=4517
%term BORU4=4518
%term BXORI4=4533
%term BXORU4=4534
%term DIVF4=4545 DIVF8=8641
%term DIVI4=4549
%term DIVU4=4550
%term MULF4=4561 MULF8=8657
%term MULI4=4565
%term MULU4=4566
%term EQF4=4577 EQF8=8673
%term EQI4=4581
%term EQU4=4582
%term GEF4=4593 GEF8=8689
%term GEI4=4597
%term GEU4=4598
%term GTF4=4609 GTF8=8705
%term GTI4=4613
%term GTU4=4614
%term LEF4=4625 LEF8=8721
%term LEI4=4629
%term LEU4=4630
%term LTF4=4641 LTF8=8737
%term LTI4=4645
%term LTU4=4646
%term NEF4=4657 NEF8=8753
%term NEI4=4661
%term NEU4=4662
%term JUMPV=584
%term LABELV=600
%term LOADB=233
%term LOADF4=4321
%term LOADF8=8417
%term LOADI1=1253
%term LOADI2=2277
%term LOADI4=4325
%term LOADP4=4327
%term LOADU1=1254
%term LOADU2=2278
%term LOADU4=4326
%term VREGP=711
%%
stmt: reg  ""

reg:  INDIRI1(VREGP)     "# read register\n"
reg:  INDIRU1(VREGP)     "# read register\n"

reg:  INDIRI2(VREGP)     "# read register\n"
reg:  INDIRU2(VREGP)     "# read register\n"

reg:  INDIRF4(VREGP)     "# read register\n"
reg:  INDIRI4(VREGP)     "# read register\n"
reg:  INDIRP4(VREGP)     "# read register\n"
reg:  INDIRU4(VREGP)     "# read register\n"

reg:  INDIRF8(VREGP)     "# read register\n"

stmt: ASGNI1(VREGP,reg)  "# write register\n"
stmt: ASGNU1(VREGP,reg)  "# write register\n"

stmt: ASGNI2(VREGP,reg)  "# write register\n"
stmt: ASGNU2(VREGP,reg)  "# write register\n"

stmt: ASGNF4(VREGP,reg)  "# write register\n"
stmt: ASGNI4(VREGP,reg)  "# write register\n"
stmt: ASGNP4(VREGP,reg)  "# write register\n"
stmt: ASGNU4(VREGP,reg)  "# write register\n"

stmt: ASGNF8(VREGP,reg)  "# write register\n"

con: CNSTI1  "%a"
con: CNSTU1  "%a"

con: CNSTI2  "%a"
con: CNSTU2  "%a"

con: CNSTI4  "%a"
con: CNSTU4  "%a"
con: CNSTP4  "%a"

reg: con     "# arbitrary constant\n" 2
reg: ADDRGP4 "\tldr\t%c, [pc, #0]\n\tmov\tpc, pc\n\tdcd\t%a\n"  2
reg: ADDRFP4 "# arbitrary offset\n"   2
reg: ADDRLP4 "# arbitrary offset\n"   2

rc:  reg    "%0"
rc:  CNSTI1 " #%a"
rc:  CNSTU1 " #%a"
rc:  CNSTI2 " #%a"  imm(a)
rc:  CNSTU2 " #%a"  imm(a)
rc:  CNSTI4 " #%a"  imm(a)
rc:  CNSTU4 " #%a"  imm(a)
rc:  CNSTP4 " #%a"  imm(a)
rc5: CNSTI1 " #%a"  range(a,1,32)
rc5: CNSTU1 " #%a"  range(a,1,32)
rc5: CNSTI2 " #%a"  range(a,1,32)
rc5: CNSTU2 " #%a"  range(a,1,32)
rc5: CNSTI4 " #%a"  range(a,1,32)
rc5: CNSTU4 " #%a"  range(a,1,32)
rc5: reg    "%0"
rc: LSHI4(reg,rc5)  "%0, asl %1"
rc: LSHU4(reg,rc5)  "%0, lsl %1"
rc: RSHI4(reg,rc5)  "%0, asr %1"
rc: RSHU4(reg,rc5)  "%0, lsr %1"

bra: ADDRGP4  "%a"
bra: con      "%0"

reg: CVII4(reg)  "\tmov\t%c, %0, lsl#8*(4-%a)\n\tmov\t%c, %c, asr#8*(4-%a)\n"  1
reg: CVII4(INDIRI1(reg))  "\tldrb\t%c, [%0, #0]\n\tmov\t%c, %c, lsl#24\n\tmov\t%c, %c, asr#24\n"  2
reg: CVII4(INDIRI2(reg))  "\tldrb\tip, [%0, #1]\n\tldrb\t%c, [%0, #0]\n\tadd\t%c, %c, ip, lsl#8\n\tmov\t%c, %c, lsl#16\n\tmov\t%c, %c, asr#16\n"  8
reg: CVUI4(reg)  "\tand\t%c, %0, #&ff\n"  (a->syms[0]->u.c.v.i == 1 ? 1 : LBURG_MAX)
reg: CVUI4(reg)  "\tbic\t%c, %0, #&ff000000\n\tand\t%c, %c, #&ff0000\n"  2
reg: CVUI4(INDIRU1(reg))  "\tldrb\t%c, [%0, #0]\n"  2
reg: CVUI4(INDIRU2(reg))  "\tldrb\tip, [%0, #1]\n\tldrb\t%c, [%0, #0]\n\tadd\t%c, %c, ip, lsl#8\n"  6
reg: CVUU4(reg)  "\tand\t%c, %0, #&ff\n"  (a->syms[0]->u.c.v.i == 1 ? 1 : LBURG_MAX)
reg: CVUU4(reg)  "\tbic\t%c, %0, #&ff000000\n\tand\t%c, %c, #&ff0000\n"  2
reg: CVUU4(INDIRU1(reg))  "\tldrb\t%c, [%0, #0]\n"  2
reg: CVUU4(INDIRU2(reg))  "\tldrb\tip, [%0, #1]\n\tldrb\t%c, [%0, #0]\n\tadd\t%c, %c, ip, lsl#8\n"  6

reg: CVFF4(reg)  "%0"  		    notarget(a)
reg: CVFF4(reg)  "\tmvfs\t%c, %0\n" move(a)
reg: CVFF8(reg)  "%0"  		    notarget(a)
reg: CVFF8(reg)  "\tmvfd\t%c, %0\n" move(a)

reg: CVFI4(reg)  "\tfix\t%c, %0\n"   1
reg: CVIF4(reg)  "\tflts\t%c, %0\n"  1
reg: CVIF8(reg)  "\tfltd\t%c, %0\n"  1

reg: INDIRI1(reg)     "\tldrb\t%c, [%0, #0]\n\tmov\t%c, %c, lsl#24\n\tmov\t%c, %c, asr#24\n"  4
reg: INDIRU1(reg)     "\tldrb\t%c, [%0, #0]\n"  2
reg: INDIRI2(reg)     "\tldrb\tip, [%0, #1]\n\tldrb\t%c, [%0, #0]\n\tadd\t%c, %c, ip, lsl#8\n\tmov\t%c, %c, lsl#16\n\tmov\t%c, %c, asr#16\n"  8
reg: INDIRU2(reg)     "\tldrb\tip, [%0, #1]\n\tldrb\t%c, [%0, #0]\n\tadd\t%c, %c, ip, lsl#8\n"  6
reg: INDIRI4(reg)     "\tldr\t%c, [%0, #0]\n"   2
reg: INDIRU4(reg)     "\tldr\t%c, [%0, #0]\n"   2
reg: INDIRP4(reg)     "\tldr\t%c, [%0, #0]\n"   2
reg: INDIRF4(reg)     "\tldfs\t%c, [%0, #0]\n"  2
reg: INDIRF8(reg)     "\tldfd\t%c, [%0, #0]\n"  2

stmt: ASGNI1(reg,reg)  "\tstrb\t%1, [%0, #0]\n"  2
stmt: ASGNU1(reg,reg)  "\tstrb\t%1, [%0, #0]\n"  2
stmt: ASGNI2(reg,reg)  "\tstrb\t%1, [%0, #0]\n\tmov\tip, %1, lsr#8\n\tstrb\tip, [%0, #1]\n"   5
stmt: ASGNU2(reg,reg)  "\tstrb\t%1, [%0, #0]\n\tmov\tip, %1, lsr#8\n\tstrb\tip, [%0, #1]\n"   5
stmt: ASGNI4(reg,reg)  "\tstr\t%1, [%0, #0]\n"   2
stmt: ASGNU4(reg,reg)  "\tstr\t%1, [%0, #0]\n"   2
stmt: ASGNP4(reg,reg)  "\tstr\t%1, [%0, #0]\n"   2
stmt: ASGNF4(reg,reg)  "\tstfs\t%1, [%0, #0]\n"  2
stmt: ASGNF8(reg,reg)  "\tstfd\t%1, [%0, #0]\n"  2
stmt: ASGNB(reg,INDIRB(reg))  "# asgnb %0 %1\n"        3

reg: LOADI1(reg)  "\tmov\t%c, %0\n"     move(a)
reg: LOADU1(reg)  "\tmov\t%c, %0\n"     move(a)
reg: LOADI2(reg)  "\tmov\t%c, %0\n"     move(a)
reg: LOADU2(reg)  "\tmov\t%c, %0\n"     move(a)
reg: LOADI4(reg)  "\tmov\t%c, %0\n"     move(a)
reg: LOADP4(reg)  "\tmov\t%c, %0\n"     move(a)
reg: LOADU4(reg)  "\tmov\t%c, %0\n"     move(a)
reg: LOADF4(reg)  "\tmvfs\t%c, %0\n"    move(a)
reg: LOADF8(reg)  "\tmvfd\t%c, %0\n"    move(a)

reg: NEGI4(reg)   "\trsb\t%c, %0, #0\n"  1
reg: NEGF4(reg)   "\tmnfs\t%c, %0\n"     1
reg: NEGF8(reg)   "\tmnfd\t%c, %0\n"     1

reg: BCOMI4(rc)      "\tmvn\t%c, %0\n"      1
reg: BCOMU4(rc)      "\tmvn\t%c, %0\n"      1
reg: BANDI4(reg,rc)  "\tand\t%c, %0, %1\n"  1
reg: BANDU4(reg,rc)  "\tand\t%c, %0, %1\n"  1
reg: BORI4(reg,rc)   "\torr\t%c, %0, %1\n"  1
reg: BORU4(reg,rc)   "\torr\t%c, %0, %1\n"  1
reg: BXORI4(reg,rc)  "\teor\t%c, %0, %1\n"  1
reg: BXORU4(reg,rc)  "\teor\t%c, %0, %1\n"  1

reg: LSHI4(reg,rc)  "\tmov\t%c, %0, asl %1\n"  1
reg: LSHU4(reg,rc)  "\tmov\t%c, %0, lsl %1\n"  1
reg: RSHI4(reg,rc)  "\tmov\t%c, %0, asr %1\n"  1
reg: RSHU4(reg,rc)  "\tmov\t%c, %0, lsr %1\n"  1

reg: ADDI4(reg,rc)   "\tadd\t%c, %0, %1\n"   1
reg: ADDP4(reg,rc)   "\tadd\t%c, %0, %1\n"   1
reg: ADDU4(reg,rc)   "\tadd\t%c, %0, %1\n"   1
reg: ADDF4(reg,reg)  "\tadfs\t%c, %0, %1\n"  1
reg: ADDF8(reg,reg)  "\tadfd\t%c, %0, %1\n"  1

reg: SUBI4(reg,rc)   "\tsub\t%c, %0, %1\n"   1
reg: SUBP4(reg,rc)   "\tsub\t%c, %0, %1\n"   1
reg: SUBU4(reg,rc)   "\tsub\t%c, %0, %1\n"   1
reg: SUBF4(reg,reg)  "\tsufs\t%c, %0, %1\n"  1
reg: SUBF8(reg,reg)  "\tsufd\t%c, %0, %1\n"  1

reg: MULI4(reg,reg)  "# mul\n"               1
reg: MULU4(reg,reg)  "# mul\n"               1
reg: MULF4(reg,reg)  "\tfmls\t%c, %0, %1\n"  1
reg: MULF8(reg,reg)  "\tmufd\t%c, %0, %1\n"  1

reg: DIVI4(reg,reg)  "\tbl\t|x$divide|\n"    2
reg: DIVU4(reg,reg)  "\tbl\t|x$udivide|\n"   2
reg: DIVF4(reg,reg)  "\tfdvs\t%c, %0, %1\n"  1
reg: DIVF8(reg,reg)  "\tdvfd\t%c, %0, %1\n"  1

reg: MODI4(reg,reg)  "\tbl\t|x$remainder|\n"    1
reg: MODU4(reg,reg)  "\tbl\t|x$uremainder|\n"   1

stmt: LABELV  "%a\n"

stmt: JUMPV(bra)  "\tb\t%0\n"        1
stmt: JUMPV(reg)  "\tmov\tpc, %0\n"  1

stmt: EQI4(reg,rc)  "\tcmp\t%0, %1\n\tbeq\t%a\n"   2
stmt: EQU4(reg,rc)  "\tcmp\t%0, %1\n\tbeq\t%a\n"   2
stmt: GEI4(reg,rc)  "\tcmp\t%0, %1\n\tbge\t%a\n"   2
stmt: GEU4(reg,rc)  "\tcmp\t%0, %1\n\tbhs\t%a\n"   2
stmt: GTI4(reg,rc)  "\tcmp\t%0, %1\n\tbgt\t%a\n"   2
stmt: GTU4(reg,rc)  "\tcmp\t%0, %1\n\tbhi\t%a\n"   2
stmt: LEI4(reg,rc)  "\tcmp\t%0, %1\n\tble\t%a\n"   2
stmt: LEU4(reg,rc)  "\tcmp\t%0, %1\n\tbls\t%a\n"   2
stmt: LTI4(reg,rc)  "\tcmp\t%0, %1\n\tblt\t%a\n"   2
stmt: LTU4(reg,rc)  "\tcmp\t%0, %1\n\tblo\t%a\n"   2
stmt: NEI4(reg,rc)  "\tcmp\t%0, %1\n\tbne\t%a\n"   2
stmt: NEU4(reg,rc)  "\tcmp\t%0, %1\n\tbne\t%a\n"   2

stmt: EQF4(reg,reg)  "\tcmf\t%0, %1\n\tbeq\t%a\n"  2
stmt: EQF8(reg,reg)  "\tcmf\t%0, %1\n\tbeq\t%a\n"  2
stmt: LEF4(reg,reg)  "\tcmfe\t%0, %1\n\tble\t%a\n" 2
stmt: LEF8(reg,reg)  "\tcmfe\t%0, %1\n\tble\t%a\n" 2
stmt: LTF4(reg,reg)  "\tcmfe\t%0, %1\n\tblt\t%a\n" 2
stmt: LTF8(reg,reg)  "\tcmfe\t%0, %1\n\tblt\t%a\n" 2
stmt: GEF4(reg,reg)  "\tcmfe\t%0, %1\n\tbge\t%a\n" 2
stmt: GEF8(reg,reg)  "\tcmfe\t%0, %1\n\tbge\t%a\n" 2
stmt: GTF4(reg,reg)  "\tcmfe\t%0, %1\n\tbgt\t%a\n" 2
stmt: GTF8(reg,reg)  "\tcmfe\t%0, %1\n\tbgt\t%a\n" 2
stmt: NEF4(reg,reg)  "\tcmf\t%0, %1\n\tbne\t%a\n"  2
stmt: NEF8(reg,reg)  "\tcmf\t%0, %1\n\tbne\t%a\n"  2

stmt: ARGI4(reg)         "# arg\n"  1
stmt: ARGP4(reg)         "# arg\n"  1
stmt: ARGU4(reg)         "# arg\n"  1
stmt: ARGF4(reg)         "# arg\n"  1
stmt: ARGF8(reg)         "# arg\n"  1
stmt: ARGB(INDIRB(reg))  "# argb %0\n"  1

stmt: CALLV(bra)   "\tbl\t%0\n"  1
reg:  CALLI4(bra)  "\tbl\t%0\n"  1
reg:  CALLP4(bra)  "\tbl\t%0\n"  1
reg:  CALLU4(bra)  "\tbl\t%0\n"  1
reg:  CALLF4(bra)  "\tbl\t%0\n"  1
reg:  CALLF8(bra)  "\tbl\t%0\n"  1

stmt: CALLV(reg)   "\tmov\tlr, pc\n\tmov\tpc, %0\n"  2
reg:  CALLI4(reg)  "\tmov\tlr, pc\n\tmov\tpc, %0\n"  2
reg:  CALLP4(reg)  "\tmov\tlr, pc\n\tmov\tpc, %0\n"  2
reg:  CALLU4(reg)  "\tmov\tlr, pc\n\tmov\tpc, %0\n"  2
reg:  CALLF4(reg)  "\tmov\tlr, pc\n\tmov\tpc, %0\n"  2
reg:  CALLF8(reg)  "\tmov\tlr, pc\n\tmov\tpc, %0\n"  2

stmt: RETV(reg)   "# ret\n"  1
stmt: RETI4(reg)  "# ret\n"  1
stmt: RETP4(reg)  "# ret\n"  1
stmt: RETU4(reg)  "# ret\n"  1
stmt: RETF4(reg)  "# ret\n"  1
stmt: RETF8(reg)  "# ret\n"  1

spill: ADDRLP4	"%a+%F"
stmt: ASGNI1(spill,reg)  "\tldr\tip, [pc, #0]\n\tmov\tpc, pc\n\tdcd\t%0\n\tstrb\t%1, [sp, ip]\n"
stmt: ASGNU1(spill,reg)  "\tldr\tip, [pc, #0]\n\tmov\tpc, pc\n\tdcd\t%0\n\tstrb\t%1, [sp, ip]\n"
stmt: ASGNI2(spill,reg)  "\tldr\tip, [pc, #0]\n\tmov\tpc, pc\n\tdcd\t%0\n\tadd\tip, ip, sp\n\tstr\ta1, [sp, #-4]!\n\tstrb\t%1, [ip, #0]\n\tmov\ta1, %1, lsr#8\n\tstrb\ta1, [ip, #1]\n\tldr\ta1, [sp], #4\n"
stmt: ASGNU2(spill,reg)  "\tldr\tip, [pc, #0]\n\tmov\tpc, pc\n\tdcd\t%0\n\tadd\tip, ip, sp\n\tstr\ta1, [sp, #-4]!\n\tstrb\t%1, [ip, #0]\n\tmov\ta1, %1, lsr#8\n\tstrb\ta1, [ip, #1]\n\tldr\ta1, [sp], #4\n"
stmt: ASGNI4(spill,reg)  "\tldr\tip, [pc, #0]\n\tmov\tpc, pc\n\tdcd\t%0\n\tstr\t%1, [sp, ip]\n"
stmt: ASGNP4(spill,reg)  "\tldr\tip, [pc, #0]\n\tmov\tpc, pc\n\tdcd\t%0\n\tstr\t%1, [sp, ip]\n"
stmt: ASGNU4(spill,reg)  "\tldr\tip, [pc, #0]\n\tmov\tpc, pc\n\tdcd\t%0\n\tstr\t%1, [sp, ip]\n"
stmt: ASGNF4(spill,reg)  "\tldr\tip, [pc, #0]\n\tmov\tpc, pc\n\tdcd\t%0\n\tadd\tip, ip, sp\n\tstfs\t%1, [ip, #0]\n"
stmt: ASGNF8(spill,reg)  "\tldr\tip, [pc, #0]\n\tmov\tpc, pc\n\tdcd\t%0\n\tadd\tip, ip, sp\n\tstfd\t%1, [ip, #0]\n"
%%
static void progend() {
	print("\tALIGN\t4\n");
	print("\tEND\n");
}
static void progbeg(argc, argv) int argc; char *argv[]; {
	int i;

	{
		union {
			char c;
			int i;
		} u;
		u.i = 0;
		u.c = 1;
		swap = ((int)(u.i == 1)) != ((int)IR->little_endian);
	}
	parseflags(argc, argv);
	for (i = 0; i < 8; i ++)
		freg[i] = mkreg("f%d", i, 1, FREG);
	for (i = 0; i < 16; i++) {
		if (i < 4)
			ireg[i] = mkreg(stringf("a%d", i + 1), i, 1, IREG);
		else if (i < 10)
			ireg[i] = mkreg(stringf("v%d", i - 3), i, 1, IREG);
		else
			ireg[i] = mkreg(NULL, i, 1, IREG);
	}
	ireg[10]->x.name = "sl";
	ireg[11]->x.name = "fp";
	ireg[12]->x.name = "ip";
	ireg[13]->x.name = "sp";
	ireg[14]->x.name = "lr";
	ireg[15]->x.name = "pc";
        fregw = mkwildcard(freg);
        iregw = mkwildcard(ireg);
	tmask[IREG] = INTTMP; tmask[FREG] = FLTTMP;
	vmask[IREG] = INTVAR; vmask[FREG] = FLTVAR;
}
static Symbol rmap(int opk) {
        switch (optype(opk)) {
        case I: case U: case P: case B:
                return iregw;
        case F:
                return fregw;
        default:
                return 0;
        }
}
static void target(p) Node p; {
	int n;

	assert(p);
	switch (specific(p->op)) {
	case CALL+F:
		setreg(p, freg[0]);     break;
	case CALL+I: case CALL+U: case CALL+P:
		setreg(p, ireg[0]);     break;
	case RET+F:
		rtarget(p, 0, freg[0]); break;
	case RET+I: case RET+U: case RET+P:
		rtarget(p, 0, ireg[0]);
		p->kids[0]->x.registered = 1;
		break;
	case ARG+I: case ARG+U: case ARG+P:
		n = p->x.argno;
		if (n < 4) {
			rtarget(p, 0, ireg[n]);
			setreg(p, ireg[n]);
		}
		break;
	case DIV+I: case DIV+U: case MOD+I: case MOD+U:
		setreg(p, ireg[0]);
		rtarget(p, 1, ireg[0]);
		rtarget(p, 0, ireg[1]);
		break;
	}
}
static void clobber(p) Node p; {
	int n;

	assert(p);
	switch (specific(p->op)) {
	case CALL+F: case CALL+I: case CALL+U: case CALL+P: case CALL+V:
		spill(0xf, FREG, p);
		break;
	}
}
static int imm(p) Node p; {
	unsigned long v;
	Symbol s = p->syms[0];

	switch (specific(p->op)) {
		case CNST+I:  v = s->u.c.v.i; break;
		case CNST+U:  v = s->u.c.v.u; break;
		case CNST+P:  if (s->u.c.v.p == 0) return 0;
		default:  return LBURG_MAX;
	}
	return imm_const(v);
}
static int imm_const(v) unsigned v; {
	int i;

	for (i = 0; i < 32; i += 2) {
		v = (v << 2) + (v >> 30);
		if (v < 0x100) return 0;
	}
	return LBURG_MAX;
}
static void emit2(p) Node p; {
	int src, dst, n, tmp;

	switch (specific(p->op)) {
	case ARG+I: case ARG+U: case ARG+P:
		n = p->x.argno;
		if (n >= 4) {
			src = getregnum(p->x.kids[0]);
			print("\tstr\t%s, [sp, #%d]\n",
				ireg[src]->x.name, n * 4 - 16);
		}
		break;
	case ARG+F:
		n = p->x.argno;
		src = getregnum(p->x.kids[0]);
		if (opsize(p->op) == 4) {
			print("\tstfs\t%s, [sp, #%d]\n",
				freg[src]->x.name, n * 4 - 16);
			if (n < 4)
				print("\tldr\t%s, [sp, #%d]\n",
					ireg[n]->x.name, n * 4 - 16);
		} else {
			print("\tstfd\t%s, [sp, #%d]\n",
				freg[src]->x.name, n * 4 - 16);
			if (n < 4)
				print("\tldr\t%s, [sp, #%d]\n",
					ireg[n]->x.name, n * 4 - 16);
			if (n < 3)
				print("\tldr\t%s, [sp, #%d]\n",
					ireg[n + 1]->x.name,
					(n + 1) * 4 - 16);
		}
		break;
	case ARG+B:
		{
			int size, offset;
			n = p->syms[RX]->u.c.v.i;
			size = roundup(p->syms[0]->u.c.v.i, 4);
			offset = max(16 - n, 0);
			if (offset < size)
				arm_blkcopy(13, n - 16 + offset + 16,
					getregnum(p->x.kids[0]), offset,
					size - offset);
			if (p->x.argno < 4) {
				tmp = min(p->x.argno + (size - 1) / 4, 3);
				if (tmp > p->x.argno)
					print("\tldmia\t%s, {%s-%s}\n",
						ireg[getregnum(p->x.kids[0])]->x.name,
						ireg[p->x.argno]->x.name,
						ireg[tmp]->x.name);
				else
					print("\tldr\t%s, [%s, #0]\n",
						ireg[p->x.argno]->x.name,
						ireg[getregnum(p->x.kids[0])]->x.name);
			}
		}
		break;
	case ASGN+B:
		arm_blkcopy(getregnum(p->x.kids[0]), 0,
			getregnum(p->x.kids[1]), 0,
			p->syms[0]->u.c.v.i);
		break;
	case CNST+I: case CNST+U: case CNST+P:
		dst = getregnum(p);
		arm_mov(dst, p->syms[0]->u.c.v.i);
		break;
	case ADDRF+P:
		arm_add(getregnum(p), 11, 4 - (bigargs ? 0 : sizeisave) +
			p->syms[0]->x.offset);
		break;
	case ADDRL+P:
		arm_add(getregnum(p), 13, framesize + p->syms[0]->x.offset);
		break;
	case MUL+I: case MUL+U:
		src = getregnum(p->x.kids[0]);
		n = getregnum(p->x.kids[1]);
		dst = getregnum(p);
		if (src == dst && dst == n) {
			print("\tmov\tip, %s\n", ireg[src]->x.name);
			src = 12;
		}
		if (src == dst) {
			tmp = src; src = n; n = tmp;
		}
		print("\tmul\t%s, %s, %s\n", ireg[dst]->x.name,
			ireg[src]->x.name, ireg[n]->x.name);
		break;
	}
}

static void arm_mov(dest, con) int dest; int con; {
	int inv = bitcount(con) > 16, n = 24;
	unsigned v;

	if (inv) con = ~con;
	while (n > 0 && (con & (0xc0 << n)) == 0)
		n -= 2;
	v = con & (0xff << n);
	if (inv) {
		print("\tmvn\t%s, #%d\n", ireg[dest]->x.name, v);
		con = (~con) - (~v);
	} else {
		print("\tmov\t%s, #%d\n", ireg[dest]->x.name, v);
		con -= v;
	}
	arm_add(dest, dest, con);
}
static void arm_add(dest, src, con) int dest, src; int con; {
	int n = 0;

	if (con == 0 && dest == src)
		return;
	if (con == 0) {
		print("\tmov\t%s, %s\n", ireg[dest]->x.name,
			ireg[src]->x.name);
		return;
	}
	do {
		for (; (con & 3) == 0; con >>= 2, n += 2);
		if (!(con & 0x100)) {
			print("\tadd\t%s, %s, #&%x\n",
				ireg[dest]->x.name, ireg[src]->x.name,
				(con & 0xff) << n);
			con -= con & 0xff;
		} else {
			print("\tsub\t%s, %s, #&%x\n",
				ireg[dest]->x.name, ireg[src]->x.name,
				(-con & 0xff) << n);
			con += -con & 0xff;
		}
		src = dest;
	} while (con);
}

static char *reglist(mask) unsigned mask; {
	int i, first = 1;
	static char list[16 * 4 + 1];

	list[0] = '\0';
	for (i = 0; i < 16; i++) {
		if (mask & (1<<i)) {
			if (first)
				first = 0;
			else
				strcat(list, ", ");
			strcat(list, ireg[i]->x.name);
		}
	}
	return list;
}


static void doarg(Node p) {
	assert(p && p->syms[0]);
	p->syms[RX] = intconst(mkactual(4, p->syms[0]->u.c.v.i));
	p->x.argno = p->syms[RX]->u.c.v.i / 4;
}
static void local(Symbol p) {
	if (askregvar(p, rmap(ttob(p->type))) == 0)
		mkauto(p);
}
static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls)
{
	int i, sizefsave, varargs, dumpmask = 0, reg = 0;

	for (i = 0; callee[i]; i++)
		;
	varargs = variadic(f->type)
		|| i > 0 && strcmp(callee[i-1]->name,
			"__builtin_va_alist") == 0;
	usedmask[0] = usedmask[1] = 0;
	freemask[0] = freemask[1] = ~(unsigned)0;
	offset = maxoffset = maxargoffset = 0;
	for (i = 0; callee[i]; i++) {
		Symbol p = callee[i], q = caller[i];
		int size = roundup(q->type->size, 4);
		assert(q);
		if (isfloat(p->type) || reg >= 4) {
			p->x.offset = q->x.offset = offset;
			p->x.name = q->x.name = stringd(offset);
			p->sclass = q->sclass = AUTO;
			dumpmask |= 0xffff>>(15 - reg);
			if (p->type->size == 8)
				dumpmask |= 1<<(reg + 1);
		}
		else if (p->addressed || varargs || isstruct(p->type)) {
				p->x.offset = offset;
				p->x.name = stringd(offset);
				p->sclass = q->sclass = AUTO;
				dumpmask |= 0xffff>>(16 - reg - size / 4);
		} else {
			q->type = p->type;
	        	p->sclass = q->sclass = REGISTER;
			if (askregvar(p, rmap(ttob(p->type))))
	        		q->x.name = ireg[reg]->x.name;
			else {
				p->sclass = q->sclass = AUTO;
				p->x.offset = offset;
				p->x.name = stringd(offset);
				dumpmask |= 0xffff>>(15 - reg);
			}
		}
		offset += size;
		reg += size / 4;
	}
	dumpmask &= 0xf;
	bigargs = (varargs || reg > 4) ? 1 : 0;
	assert(!caller[i]);
	offset = 0;
	gencode(caller, callee);
	maxargoffset = max(roundup(maxargoffset, 4) - 16, 0);
	sizefsave = 12*bitcount(usedmask[FREG] & 0xf0);
	sizeisave = 16 + 4*bitcount(usedmask[IREG] & 0x3f0) +
		4*bitcount(dumpmask);
	framesize = roundup(sizefsave + sizeisave + maxargoffset + maxoffset,
		4);
	segment(CODE);
	if (glevel) {
		print("\tALIGN\t4\n");
		defstring(strlen(f->x.name) + 1, f->x.name);
		print("\tALIGN\t4\n");
		print("\tdcd\t&%x\n", 0xff000000 | ((strlen(f->x.name) + 4) &
~3));
	}
	print("\tALIGN\t4\n");
	print("%s\n", f->x.name);
	print("\tmov\tip, sp\n");
	if (bigargs) {
		print("\tstmfd\tsp!, {a1-a4}\n");
		print("\tstmfd\tsp!, {%s}\n",
			reglist((usedmask[IREG] & 0x3f0) | savelist));
	} else {
		print("\tstmfd\tsp!, {%s}\n",
			reglist(dumpmask | (usedmask[IREG] & 0x3f0)
				| savelist));
	}
	for (i = 7; i >= 4; i--)
		if (usedmask[FREG] & (1<<i))
			print("\tstfe\t%s, [sp, #-12]!\n", freg[i]->x.name);
	print("\tsub\tfp, ip, #%d\n", bigargs ? 20 : 4);
	if (framesize + 16 > 256) {
		arm_add(12, 13, -(framesize + 16));
		print("\tcmp\tip, sl\n");
		print("\tbllt\t|x$stack_overflow_1|\n");
	} else {
	    	print("\tcmp\tsp, sl\n");
    	        print("\tbllt\t|x$stack_overflow|\n");
    	}
	if (framesize - sizefsave - sizeisave > 0)
		arm_add(13, 13, -(framesize - sizefsave - sizeisave));
	for (i = 0; i < 4 && callee[i]; i++)
		if (caller[i]->sclass == REGISTER &&
			callee[i]->sclass == REGISTER &&
			caller[i]->type == callee[i]->type)
			print("\tmov\t%s, %s\n", callee[i]->x.name,
				caller[i]->x.name);
	i = framesize;
	framesize -= sizefsave + sizeisave;
	emitcode();
	framesize = i;
	for (i = 4; i <= 7; i++)
		if (usedmask[FREG] & (1<<i))
			print("\tldfe\t%s, [fp, #-%d]\n", freg[i]->x.name,
				sizeisave - 4 * bitcount(dumpmask) +
				(8 - i) * 12 - 4);
	print("\tldmea\tfp, {%s}^\n",
		reglist((usedmask[IREG] & 0x3f0) | reslist));
}
static void defconst(int suffix, int size, Value v) {
	if (suffix == F && size == 4) {
 		float f = v.d;
 		print("\tdcd\t&%x\n", *(unsigned *)&f); return;
	}
	else if (suffix == F && size == 8) {
  		double d = v.d;
  		unsigned *p = (unsigned *)&d;
  		print("\tdcd\t&%x, &%x\n", p[swap], p[!swap]);
	}
	else if (suffix == P)
		print("\tdcd\t&%x\n", v.p);
	else if (size == 1)
		print("\tdcb\t%d\n", suffix == I ? (signed char)v.i : (unsigned char)v.u);
	else if (size == 2)
		print("\tdcw\t%d\n", suffix == I ? (short)v.i : (unsigned short)v.u);
	else if (size == 4)
		print("\tdcd\t%d\n", suffix == I ? (int)v.i : (unsigned)v.u);
}
static void defaddress(Symbol p) {
	print("\tdcd\t%s\n", p->x.name);
}
static void defstring(int n, char *str) {
	int mode, oldmode = 0;
	char *s, c;

	print("\t=\t");
	for (s = str; s < str + n; s++) {
	    	c = (*s) & 0xff;
	    	mode = (isprint(c) && c != '\"' && c != '\\') ? 1 : 0;
	    	if (oldmode && !mode)
	    		print("\",");
	    	else if (!oldmode && mode)
	    		print("\"");
	    	print(mode ? "%c" : "&%x", c);
	    	if (!mode && s < str + n - 1)
	    		print(",");
	    	oldmode = mode;
	}
	if (mode)
		print("\"");
	print("\n");
}
static void export(Symbol p) {
	print("\tEXPORT\t%s\n", p->x.name);
}
static void import(Symbol p) {}
static void defsymbol(Symbol p) {
	if (p->scope >= LOCAL && p->sclass == STATIC)
		p->x.name = stringf("|L..%d|", genlabel(1));
	else if (p->generated)
		p->x.name = stringf("|L..%s|", p->name);
	else
		assert(p->scope != CONSTANTS || isint(p->type) || isptr(p->type)),
		p->x.name = p->name;
}
static void address(Symbol q, Symbol p, int n) {
	q->x.offset = p->x.offset + n;
	if (p->scope == GLOBAL
	|| p->sclass == STATIC || p->sclass == EXTERN)
		q->x.name = stringf("%s%s%d", p->x.name,
			n >= 0 ? "+" : "", n);
	else
		q->x.name = stringf("%d", q->x.offset);
}
static void global(Symbol p) {
	if (p->u.seg == BSS) {
		if (p->sclass == STATIC || Aflag >= 2) {
			if (cseg != BSS)
				print("\tAREA\t|C$$zidata|, DATA, NOINIT\n");
			if (p->type->align > 1)
				print("\tALIGN\t%d\n", p->type->align);
			print("%s\n\t%%\t%d\n", p->x.name, p->type->size);
		} else {
			print("\tAREA\t%s, COMMON, NOINIT\n", p->x.name);
			if (p->type->align > 1)
				print("\tALIGN\t%d\n", p->type->align);
			print("\t%%\t%d\n", p->type->size);
		}
		print("\tAREA\t|C$$code|, CODE, READONLY\n");
	} else {
		if (p->u.seg == DATA)
			print("\tAREA\t|C$$data|, DATA\n");
		if (p->type->align > 1)
			print("\tALIGN\t%d\n", p->type->align);
		print("%s\n", p->x.name);
	}
}
static void segment(int n) {
	if (cseg == n) return;
	cseg = n;
	switch (n) {
	case CODE: case LIT:
		print("\tAREA\t|C$$code|, CODE, READONLY\n"); break;
	case BSS:  print("\tAREA\t|C$$zidata|, DATA, NOINIT\n"); break;
	}
}
static void space(int n) {
	if (cseg != BSS)
		print("\t%%\t%d\n", n);
}
static void arm_blkcopy(int dreg, int doffset, int sreg, int soffset, int size)
{
	print("\tstmfd\tsp!, {a1-a4}\n");
	arm_add(0, dreg, doffset);
	arm_add(1, sreg, soffset);
	arm_mov(2, size);
	print("\tbl\tmemcpy\n");
	print("\tldmfd\tsp!, {a1-a4}\n");
}
static void blkloop(int dreg, int doff, int sreg, int soff, int size, int tmps[]) {}
static void blkfetch(int size, int off, int reg, int tmp) {}
static void blkstore(int size, int off, int reg, int tmp) {}

static int bitcount(unsigned mask) {
	unsigned i, n = 0;

	for (i = 1; i; i <<= 1)
		if (mask&i)
			n++;
	return n;
}

Interface armIR = {
	1, 1, 0,  /* char */
	2, 2, 0,  /* short */
	4, 4, 0,  /* int */
	4, 4, 0,  /* long */
	4, 4, 1,  /* float */
	8, 4, 1,  /* double */
	8, 4, 1,  /* long double */
	4, 4, 0,  /* T * */
	0, 4, 0,  /* struct */
	1,  /* little_endian */
	1,  /* mulops_calls */
	0,  /* wants_callb */
	1,  /* wants_argb */
	1,  /* left_to_right */
	0,  /* wants_dag */
	address,
	blockbeg,
	blockend,
	defaddress,
	defconst,
	defstring,
	defsymbol,
	emit,
	export,
	function,
	gen,
	global,
	import,
	local,
	progbeg,
	progend,
	segment,
	space,
	0, 0, 0, 0, 0, 0, 0,
	{
		1,	/* max_unaligned_load */
		rmap,
		blkfetch, blkstore, blkloop,
		_label,
		_rule,
		_nts,
		_kids,
		_string,
		_templates,
		_isinstruction,
		_ntname,
		emit2,
		doarg,
		target,
		clobber,

	}
};
