Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
145 halyavin 1
/*
2
 *  ARMv4 code generator for TCC
3
 *
4
 *  Copyright (c) 2003 Daniel Glöckner
5
 *
6
 *  Based on i386-gen.c by Fabrice Bellard
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
 */
22
 
23
/* number of available registers */
24
#define NB_REGS             9
25
 
26
/* a register can belong to several classes. The classes must be
27
   sorted from more general to more precise (see gv2() code which does
28
   assumptions on it). */
29
#define RC_INT     0x0001 /* generic integer register */
30
#define RC_FLOAT   0x0002 /* generic float register */
31
#define RC_R0      0x0004
32
#define RC_R1      0x0008
33
#define RC_R2      0x0010
34
#define RC_R3      0x0020
35
#define RC_R12     0x0040
36
#define RC_F0      0x0080
37
#define RC_F1      0x0100
38
#define RC_F2      0x0200
39
#define RC_F3      0x0400
40
#define RC_IRET    RC_R0  /* function return: integer register */
41
#define RC_LRET    RC_R1  /* function return: second integer register */
42
#define RC_FRET    RC_F0  /* function return: float register */
43
 
44
/* pretty names for the registers */
45
enum {
46
    TREG_R0 = 0,
47
    TREG_R1,
48
    TREG_R2,
49
    TREG_R3,
50
    TREG_R12,
51
    TREG_F0,
52
    TREG_F1,
53
    TREG_F2,
54
    TREG_F3,
55
};
56
 
57
int reg_classes[NB_REGS] = {
58
    /* r0 */ RC_INT | RC_R0,
59
    /* r1 */ RC_INT | RC_R1,
60
    /* r2 */ RC_INT | RC_R2,
61
    /* r3 */ RC_INT | RC_R3,
62
    /* r12 */ RC_INT | RC_R12,
63
    /* f0 */ RC_FLOAT | RC_F0,
64
    /* f1 */ RC_FLOAT | RC_F1,
65
    /* f2 */ RC_FLOAT | RC_F2,
66
    /* f3 */ RC_FLOAT | RC_F3,
67
};
68
 
69
static int two2mask(int a,int b) {
70
  return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT);
71
}
72
 
73
static int regmask(int r) {
74
  return reg_classes[r]&~(RC_INT|RC_FLOAT);
75
}
76
 
77
/* return registers for function */
78
#define REG_IRET TREG_R0 /* single word int return register */
79
#define REG_LRET TREG_R1 /* second word return register (for long long) */
80
#define REG_FRET TREG_F0 /* float return register */
81
 
82
/* defined if function parameters must be evaluated in reverse order */
83
#define INVERT_FUNC_PARAMS
84
 
85
/* defined if structures are passed as pointers. Otherwise structures
86
   are directly pushed on stack. */
87
//#define FUNC_STRUCT_PARAM_AS_PTR
88
 
89
/* pointer size, in bytes */
90
#define PTR_SIZE 4
91
 
92
/* long double size and alignment, in bytes */
93
#define LDOUBLE_SIZE  8
94
#define LDOUBLE_ALIGN 4
95
/* maximum alignment (for aligned attribute support) */
96
#define MAX_ALIGN     8
97
 
98
#define CHAR_IS_UNSIGNED
99
 
100
/******************************************************/
101
/* ELF defines */
102
 
103
#define EM_TCC_TARGET EM_ARM
104
 
105
/* relocation type for 32 bit data relocation */
106
#define R_DATA_32   R_ARM_ABS32
107
#define R_JMP_SLOT  R_ARM_JUMP_SLOT
108
#define R_COPY      R_ARM_COPY
109
 
110
#define ELF_START_ADDR 0x00008000
111
#define ELF_PAGE_SIZE  0x1000
112
 
113
/******************************************************/
114
static unsigned long func_sub_sp_offset,last_itod_magic;
115
 
116
void o(unsigned long i)
117
{
118
  /* this is a good place to start adding big-endian support*/
119
  int ind1;
120
 
121
  ind1 = ind + 4;
122
  if (!cur_text_section)
123
    error("compiler error! This happens f.ex. if the compiler\n"
124
         "can't evaluate constant expressions outside of a function.");
125
  if (ind1 > cur_text_section->data_allocated)
126
    section_realloc(cur_text_section, ind1);
127
  cur_text_section->data[ind++] = i&255;
128
  i>>=8;
129
  cur_text_section->data[ind++] = i&255;
130
  i>>=8;
131
  cur_text_section->data[ind++] = i&255;
132
  i>>=8;
133
  cur_text_section->data[ind++] = i;
134
}
135
 
136
static unsigned long stuff_const(unsigned long op,unsigned long c)
137
{
138
  int try_neg=0;
139
  unsigned long nc = 0,negop = 0;
140
 
141
  switch(op&0x1F00000)
142
  {
143
    case 0x800000: //add
144
    case 0x400000: //sub
145
      try_neg=1;
146
      negop=op^0xC00000;
147
      nc=-c;
148
      break;
149
    case 0x1A00000: //mov
150
    case 0x1E00000: //mvn
151
      try_neg=1;
152
      negop=op^0x400000;
153
      nc=~c;
154
      break;
155
    case 0x200000: //xor
156
      if(c==~0)
157
	return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000;
158
      break;
159
    case 0x0: //and
160
      if(c==~0)
161
	return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000;
162
    case 0x1C00000: //bic
163
      try_neg=1;
164
      negop=op^0x1C00000;
165
      nc=~c;
166
      break;
167
    case 0x1800000: //orr
168
      if(c==~0)
169
	return (op&0xFFF0FFFF)|0x1E00000;
170
      break;
171
  }
172
  do {
173
    unsigned long m;
174
    int i;
175
    if(c<256) /* catch undefined <<32 */
176
      return op|c;
177
    for(i=2;i<32;i+=2) {
178
      m=(0xff>>i)|(0xff<<(32-i));
179
      if(!(c&~m))
180
	return op|(i<<7)|(c<>(32-i));
181
    }
182
    op=negop;
183
    c=nc;
184
  } while(try_neg--);
185
  return 0;
186
}
187
 
188
 
189
//only add,sub
190
void stuff_const_harder(unsigned long op,unsigned long v) {
191
  unsigned long x;
192
  x=stuff_const(op,v);
193
  if(x)
194
    o(x);
195
  else {
196
    unsigned long a[16],nv,no,o2,n2;
197
    int i,j,k;
198
    a[0]=0xff;
199
    o2=(op&0xfff0ffff)|((op&0xf000)<<4);;
200
    for(i=1;i<16;i++)
201
      a[i]=(a[i-1]>>2)|(a[i-1]<<30);
202
    for(i=0;i<12;i++)
203
      for(j=i+4;i<13+i;i++)
204
	if((v&(a[i]|a[j]))==v) {
205
	  o(stuff_const(op,v&a[i]));
206
	  o(stuff_const(o2,v&a[j]));
207
	  return;
208
	}
209
    no=op^0xC00000;
210
    n2=o2^0xC00000;
211
    nv=-v;
212
    for(i=0;i<12;i++)
213
      for(j=i+4;i<13+i;i++)
214
	if((nv&(a[i]|a[j]))==nv) {
215
	  o(stuff_const(no,nv&a[i]));
216
	  o(stuff_const(n2,nv&a[j]));
217
	  return;
218
	}
219
    for(i=0;i<8;i++)
220
      for(j=i+4;i<12;i++)
221
	for(k=j+4;k<13+i;i++)
222
	  if((v&(a[i]|a[j]|a[k]))==v) {
223
	    o(stuff_const(op,v&a[i]));
224
	    o(stuff_const(o2,v&a[j]));
225
	    o(stuff_const(o2,v&a[k]));
226
	    return;
227
	  }
228
    no=op^0xC00000;
229
    nv=-v;
230
    for(i=0;i<8;i++)
231
      for(j=i+4;i<12;i++)
232
	for(k=j+4;k<13+i;i++)
233
	  if((nv&(a[i]|a[j]|a[k]))==nv) {
234
	    o(stuff_const(no,nv&a[i]));
235
	    o(stuff_const(n2,nv&a[j]));
236
	    o(stuff_const(n2,nv&a[k]));
237
	    return;
238
	  }
239
    o(stuff_const(op,v&a[0]));
240
    o(stuff_const(o2,v&a[4]));
241
    o(stuff_const(o2,v&a[8]));
242
    o(stuff_const(o2,v&a[12]));
243
  }
244
}
245
 
246
unsigned long encbranch(int pos,int addr,int fail)
247
{
248
  addr-=pos+8;
249
  addr/=4;
250
  if(addr>=0x1000000 || addr<-0x1000000) {
251
    if(fail)
252
      error("FIXME: function bigger than 32MB");
253
    return 0;
254
  }
255
  return 0x0A000000|(addr&0xffffff);
256
}
257
 
258
int decbranch(int pos)
259
{
260
  int x;
261
  x=*(int *)(cur_text_section->data + pos);
262
  x&=0x00ffffff;
263
  if(x&0x800000)
264
    x-=0x1000000;
265
  return x*4+pos+8;
266
}
267
 
268
/* output a symbol and patch all calls to it */
269
void gsym_addr(int t, int a)
270
{
271
  unsigned long *x;
272
  int lt;
273
  while(t) {
274
    x=(unsigned long *)(cur_text_section->data + t);
275
    t=decbranch(lt=t);
276
    if(a==lt+4)
277
      *x=0xE1A00000; // nop
278
    else {
279
      *x &= 0xff000000;
280
      *x |= encbranch(lt,a,1);
281
    }
282
  }
283
}
284
 
285
void gsym(int t)
286
{
287
  gsym_addr(t, ind);
288
}
289
 
290
static unsigned long fpr(int r)
291
{
292
  if(rTREG_F3)
293
    error("compiler error! register %i is no fp register\n",r);
294
  return r-5;
295
}
296
 
297
static unsigned long intr(int r)
298
{
299
  if(r==4)
300
    return 12;
301
  if((r<0 || r>4) && r!=14)
302
    error("compiler error! register %i is no int register\n",r);
303
  return r;
304
}
305
 
306
static void calcaddr(unsigned long *base,int *off,int *sgn,int maxoff,unsigned shift)
307
{
308
  if(*off>maxoff || *off&((1<
309
    unsigned long x,y;
310
    x=0xE280E000;
311
    if(*sgn)
312
      x=0xE240E000;
313
    x|=(*base)<<16;
314
    *base=14; // lr
315
    y=stuff_const(x,*off&~maxoff);
316
    if(y) {
317
      o(y);
318
      *off&=maxoff;
319
      return;
320
    }
321
    y=stuff_const(x,(*off+maxoff)&~maxoff);
322
    if(y) {
323
      o(y);
324
      *sgn=!*sgn;
325
      *off=((*off+maxoff)&~maxoff)-*off;
326
      return;
327
    }
328
    stuff_const_harder(x,*off&~maxoff);
329
    *off&=maxoff;
330
  }
331
}
332
 
333
static unsigned long mapcc(int cc)
334
{
335
  switch(cc)
336
  {
337
    case TOK_ULT:
338
      return 0x30000000;
339
    case TOK_UGE:
340
      return 0x20000000;
341
    case TOK_EQ:
342
      return 0x00000000;
343
    case TOK_NE:
344
      return 0x10000000;
345
    case TOK_ULE:
346
      return 0x90000000;
347
    case TOK_UGT:
348
      return 0x80000000;
349
    case TOK_LT:
350
      return 0xB0000000;
351
    case TOK_GE:
352
      return 0xA0000000;
353
    case TOK_LE:
354
      return 0xD0000000;
355
    case TOK_GT:
356
      return 0xC0000000;
357
  }
358
  error("unexpected condition code");
359
  return 0xE0000000;
360
}
361
 
362
static int negcc(int cc)
363
{
364
  switch(cc)
365
  {
366
    case TOK_ULT:
367
      return TOK_UGE;
368
    case TOK_UGE:
369
      return TOK_ULT;
370
    case TOK_EQ:
371
      return TOK_NE;
372
    case TOK_NE:
373
      return TOK_EQ;
374
    case TOK_ULE:
375
      return TOK_UGT;
376
    case TOK_UGT:
377
      return TOK_ULE;
378
    case TOK_LT:
379
      return TOK_GE;
380
    case TOK_GE:
381
      return TOK_LT;
382
    case TOK_LE:
383
      return TOK_GT;
384
    case TOK_GT:
385
      return TOK_LE;
386
  }
387
  error("unexpected condition code");
388
  return TOK_NE;
389
}
390
 
391
/* load 'r' from value 'sv' */
392
void load(int r, SValue *sv)
393
{
394
  int v, ft, fc, fr, sign;
395
  unsigned long op;
396
  SValue v1;
397
 
398
  fr = sv->r;
399
  ft = sv->type.t;
400
  fc = sv->c.ul;
401
 
402
  if(fc>=0)
403
    sign=0;
404
  else {
405
    sign=1;
406
    fc=-fc;
407
  }
408
 
409
  v = fr & VT_VALMASK;
410
  if (fr & VT_LVAL) {
411
    unsigned long base=0xB; // fp
412
    if(v == VT_LLOCAL) {
413
      v1.type.t = VT_PTR;
414
      v1.r = VT_LOCAL | VT_LVAL;
415
      v1.c.ul = sv->c.ul;
416
      load(base=14 /* lr */, &v1);
417
      fc=sign=0;
418
      v=VT_LOCAL;
419
    } else if(v == VT_CONST) {
420
      v1.type.t = VT_PTR;
421
      v1.r = fr&~VT_LVAL;
422
      v1.c.ul = sv->c.ul;
423
      v1.sym=sv->sym;
424
      load(base=14, &v1);
425
      fc=sign=0;
426
      v=VT_LOCAL;
427
    } else if(v < VT_CONST) {
428
      base=intr(v);
429
      fc=sign=0;
430
      v=VT_LOCAL;
431
    }
432
    if(v == VT_LOCAL) {
433
      if(is_float(ft)) {
434
	calcaddr(&base,&fc,&sign,1020,2);
435
	op=0xED100100;
436
	if(!sign)
437
	  op|=0x800000;
438
#if LDOUBLE_SIZE == 8
439
	if ((ft & VT_BTYPE) != VT_FLOAT)
440
	  op|=0x8000;
441
#else
442
	if ((ft & VT_BTYPE) == VT_DOUBLE)
443
	  op|=0x8000;
444
	else if ((ft & VT_BTYPE) == VT_LDOUBLE)
445
	  op|=0x400000;
446
#endif
447
	o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
448
      } else if((ft & VT_TYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_SHORT) {
449
	calcaddr(&base,&fc,&sign,255,0);
450
	op=0xE1500090;
451
	if ((ft & VT_BTYPE) == VT_SHORT)
452
	  op|=0x20;
453
	if ((ft & VT_UNSIGNED) == 0)
454
	  op|=0x40;
455
	if(!sign)
456
	  op|=0x800000;
457
	o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
458
      } else {
459
	calcaddr(&base,&fc,&sign,4095,0);
460
	op=0xE5100000;
461
	if(!sign)
462
	  op|=0x800000;
463
        if ((ft & VT_BTYPE) == VT_BYTE)
464
          op|=0x400000;
465
        o(op|(intr(r)<<12)|fc|(base<<16));
466
      }
467
      return;
468
    }
469
  } else {
470
    if (v == VT_CONST) {
471
      op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.ul);
472
      if (fr & VT_SYM || !op) {
473
        o(0xE59F0000|(intr(r)<<12));
474
        o(0xEA000000);
475
        if(fr & VT_SYM)
476
	  greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
477
        o(sv->c.ul);
478
      } else
479
        o(op);
480
      return;
481
    } else if (v == VT_LOCAL) {
482
      op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.ul);
483
      if (fr & VT_SYM || !op) {
484
	o(0xE59F0000|(intr(r)<<12));
485
	o(0xEA000000);
486
	if(fr & VT_SYM) // needed ?
487
	  greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
488
	o(sv->c.ul);
489
	o(0xE08B0000|(intr(r)<<12)|intr(r));
490
      } else
491
	o(op);
492
      return;
493
    } else if(v == VT_CMP) {
494
      o(mapcc(sv->c.ul)|0x3A00001|(intr(r)<<12));
495
      o(mapcc(negcc(sv->c.ul))|0x3A00000|(intr(r)<<12));
496
      return;
497
    } else if (v == VT_JMP || v == VT_JMPI) {
498
      int t;
499
      t = v & 1;
500
      o(0xE3A00000|(intr(r)<<12)|t);
501
      o(0xEA000000);
502
      gsym(sv->c.ul);
503
      o(0xE3A00000|(intr(r)<<12)|(t^1));
504
      return;
505
    } else if (v < VT_CONST) {
506
      if(is_float(ft))
507
	o(0xEE008180|(fpr(r)<<12)|fpr(v));
508
      else
509
	o(0xE1A00000|(intr(r)<<12)|intr(v));
510
      return;
511
    }
512
  }
513
  error("load unimplemented!");
514
}
515
 
516
/* store register 'r' in lvalue 'v' */
517
void store(int r, SValue *sv)
518
{
519
  SValue v1;
520
  int v, ft, fc, fr, sign;
521
  unsigned long op;
522
 
523
  fr = sv->r;
524
  ft = sv->type.t;
525
  fc = sv->c.ul;
526
 
527
  if(fc>=0)
528
    sign=0;
529
  else {
530
    sign=1;
531
    fc=-fc;
532
  }
533
 
534
  v = fr & VT_VALMASK;
535
  if (fr & VT_LVAL || fr == VT_LOCAL) {
536
    unsigned long base=0xb;
537
    if(v < VT_CONST) {
538
      base=intr(v);
539
      v=VT_LOCAL;
540
      fc=sign=0;
541
    } else if(v == VT_CONST) {
542
      v1.type.t = ft;
543
      v1.r = fr&~VT_LVAL;
544
      v1.c.ul = sv->c.ul;
545
      v1.sym=sv->sym;
546
      load(base=14, &v1);
547
      fc=sign=0;
548
      v=VT_LOCAL;
549
    }
550
    if(v == VT_LOCAL) {
551
       if(is_float(ft)) {
552
	calcaddr(&base,&fc,&sign,1020,2);
553
	op=0xED000100;
554
	if(!sign)
555
	  op|=0x800000;
556
#if LDOUBLE_SIZE == 8
557
	if ((ft & VT_BTYPE) != VT_FLOAT)
558
	  op|=0x8000;
559
#else
560
	if ((ft & VT_BTYPE) == VT_DOUBLE)
561
	  op|=0x8000;
562
	if ((ft & VT_BTYPE) == VT_LDOUBLE)
563
	  op|=0x400000;
564
#endif
565
	o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
566
	return;
567
      } else if((ft & VT_BTYPE) == VT_SHORT) {
568
	calcaddr(&base,&fc,&sign,255,0);
569
	op=0xE14000B0;
570
	if(!sign)
571
	  op|=0x800000;
572
	o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
573
      } else {
574
	calcaddr(&base,&fc,&sign,4095,0);
575
	op=0xE5000000;
576
	if(!sign)
577
	  op|=0x800000;
578
        if ((ft & VT_BTYPE) == VT_BYTE)
579
          op|=0x400000;
580
        o(op|(intr(r)<<12)|fc|(base<<16));
581
      }
582
      return;
583
    }
584
  }
585
  error("store unimplemented");
586
}
587
 
588
static void gadd_sp(int val)
589
{
590
  stuff_const_harder(0xE28DD000,val);
591
}
592
 
593
/* 'is_jmp' is '1' if it is a jump */
594
static void gcall_or_jmp(int is_jmp)
595
{
596
  int r;
597
  if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
598
    unsigned long x;
599
    /* constant case */
600
    x=encbranch(ind,ind+vtop->c.ul,0);
601
    if(x) {
602
      if (vtop->r & VT_SYM) {
603
	/* relocation case */
604
	greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
605
      } else
606
	put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0);
607
      o(x|(is_jmp?0xE0000000:0xE1000000));
608
    } else {
609
      if(!is_jmp)
610
	o(0xE28FE004); // add lr,pc,#4
611
      o(0xE51FF004);   // ldr pc,[pc,#-4]
612
      if (vtop->r & VT_SYM)
613
	greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
614
      o(vtop->c.ul);
615
    }
616
  } else {
617
    /* otherwise, indirect call */
618
    r = gv(RC_INT);
619
    if(!is_jmp)
620
      o(0xE1A0E00F);       // mov lr,pc
621
    o(0xE1A0F000|intr(r)); // mov pc,r
622
  }
623
}
624
 
625
/* Generate function call. The function address is pushed first, then
626
   all the parameters in call order. This functions pops all the
627
   parameters and the function address. */
628
void gfunc_call(int nb_args)
629
{
630
  int size, align, r, args_size, i;
631
  Sym *func_sym;
632
  signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
633
  int todo=0xf, keep, plan2[4]={0,0,0,0};
634
 
635
  r = vtop->r & VT_VALMASK;
636
  if (r == VT_CMP || (r & ~1) == VT_JMP)
637
    gv(RC_INT);
638
  args_size = 0;
639
  for(i = nb_args ; i-- && args_size < 16 ;) {
640
    if ((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) {
641
      size = type_size(&vtop[-i].type, &align);
642
      size = (size + 3) & ~3;
643
      args_size += size;
644
    } else if ((vtop[-i].type.t & VT_BTYPE) == VT_FLOAT)
645
      args_size += 4;
646
    else if ((vtop[-i].type.t & VT_BTYPE) == VT_DOUBLE)
647
      args_size += 8;
648
    else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE)
649
      args_size += LDOUBLE_SIZE;
650
    else {
651
      plan[nb_args-1-i][0]=args_size/4;
652
      args_size += 4;
653
      if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) {
654
	plan[nb_args-1-i][1]=args_size/4;
655
	args_size += 4;
656
      }
657
    }
658
  }
659
  args_size = keep = 0;
660
  for(i = 0;i < nb_args; i++) {
661
    vnrott(keep+1);
662
    if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
663
      size = type_size(&vtop->type, &align);
664
      /* align to stack align size */
665
      size = (size + 3) & ~3;
666
      /* allocate the necessary size on stack */
667
      gadd_sp(-size);
668
      /* generate structure store */
669
      r = get_reg(RC_INT);
670
      o(0xE1A0000D|(intr(r)<<12));
671
      vset(&vtop->type, r | VT_LVAL, 0);
672
      vswap();
673
      vstore();
674
      vtop--;
675
      args_size += size;
676
    } else if (is_float(vtop->type.t)) {
677
      r=fpr(gv(RC_FLOAT))<<12;
678
      if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
679
        size = 4;
680
      else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
681
        size = 8;
682
      else
683
        size = LDOUBLE_SIZE;
684
 
685
      if (size == 12)
686
	r|=0x400000;
687
      else if(size == 8)
688
	r|=0x8000;
689
 
690
      o(0xED2D0100|r|(size>>2));
691
      vtop--;
692
      args_size += size;
693
    } else {
694
      int s;
695
      /* simple type (currently always same size) */
696
      /* XXX: implicit cast ? */
697
      size=4;
698
      if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
699
	lexpand_nr();
700
	s=RC_INT;
701
	if(nb_args-i<5 && plan[nb_args-i-1][1]!=-1) {
702
	  s=regmask(plan[nb_args-i-1][1]);
703
	  todo&=~(1<
704
	}
705
	if(s==RC_INT) {
706
	  r = gv(s);
707
	  o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
708
	  vtop--;
709
	} else {
710
	  plan2[keep]=s;
711
	  keep++;
712
          vswap();
713
	}
714
	size = 8;
715
      }
716
      s=RC_INT;
717
      if(nb_args-i<5 && plan[nb_args-i-1][0]!=-1) {
718
        s=regmask(plan[nb_args-i-1][0]);
719
	todo&=~(1<
720
      }
721
      if(s==RC_INT) {
722
	r = gv(s);
723
	o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
724
	vtop--;
725
      } else {
726
	plan2[keep]=s;
727
	keep++;
728
      }
729
      args_size += size;
730
    }
731
  }
732
  for(i=keep;i--;) {
733
    gv(plan2[i]);
734
    vrott(keep);
735
  }
736
  save_regs(keep); /* save used temporary registers */
737
  keep++;
738
  if(args_size) {
739
    int n;
740
    n=args_size/4;
741
    if(n>4)
742
      n=4;
743
    todo&=((1<
744
    if(todo) {
745
      int i;
746
      o(0xE8BD0000|todo);
747
      for(i=0;i<4;i++)
748
	if(todo&(1<
749
	  vpushi(0);
750
	  vtop->r=i;
751
	  keep++;
752
	}
753
    }
754
    args_size-=n*4;
755
  }
756
  vnrott(keep);
757
  func_sym = vtop->type.ref;
758
  gcall_or_jmp(0);
759
  if (args_size)
760
      gadd_sp(args_size);
761
  vtop-=keep;
762
}
763
 
764
/* generate function prolog of type 't' */
765
void gfunc_prolog(CType *func_type)
766
{
767
  Sym *sym,*sym2;
768
  int n,addr,size,align;
769
 
770
  sym = func_type->ref;
771
  func_vt = sym->type;
772
 
773
  n=0;
774
  addr=12;
775
  if((func_vt.t & VT_BTYPE) == VT_STRUCT) {
776
    func_vc = addr;
777
    addr += 4;
778
    n++;
779
  }
780
  for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) {
781
    size = type_size(&sym2->type, &align);
782
    size = (size + 3) & ~3;
783
    n+=size/4;
784
  }
785
  o(0xE1A0C00D); /* mov ip,sp */
786
  if(func_type->ref->c == FUNC_ELLIPSIS)
787
    n=4;
788
  if(n) {
789
    if(n>4)
790
      n=4;
791
    o(0xE92D0000|((1<
792
  }
793
  o(0xE92D5800); /* save fp, ip, lr*/
794
  o(0xE1A0B00D); /* mov fp,sp */
795
  func_sub_sp_offset = ind;
796
  o(0xE1A00000); /* nop, leave space for stack adjustment */
797
  while ((sym = sym->next)) {
798
    CType *type;
799
    type = &sym->type;
800
    sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
801
    size = type_size(type, &align);
802
    size = (size + 3) & ~3;
803
    addr += size;
804
  }
805
  last_itod_magic=0;
806
  loc = 0;
807
}
808
 
809
/* generate function epilog */
810
void gfunc_epilog(void)
811
{
812
  unsigned long x;
813
  o(0xE89BA800); /* restore fp, sp, pc */
814
  if(loc) {
815
    x=stuff_const(0xE24DD000, (-loc + 3) & -4); /* sub sp,sp,# */
816
    if(x)
817
      *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = x;
818
    else {
819
      unsigned long addr;
820
      addr=ind;
821
      o(0xE59FC004); /* ldr ip,[pc+4] */
822
      o(0xE04DD00C); /* sub sp,sp,ip  */
823
      o(0xE1A0F00E); /* mov pc,lr */
824
      o((-loc + 3) & -4);
825
      *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1);
826
    }
827
  }
828
}
829
 
830
/* generate a jump to a label */
831
int gjmp(int t)
832
{
833
  int r;
834
  r=ind;
835
  o(0xE0000000|encbranch(r,t,1));
836
  return r;
837
}
838
 
839
/* generate a jump to a fixed address */
840
void gjmp_addr(int a)
841
{
842
  gjmp(a);
843
}
844
 
845
/* generate a test. set 'inv' to invert test. Stack entry is popped */
846
int gtst(int inv, int t)
847
{
848
  int v, r;
849
  unsigned long op;
850
  v = vtop->r & VT_VALMASK;
851
  r=ind;
852
  if (v == VT_CMP) {
853
    op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
854
    op|=encbranch(r,t,1);
855
    o(op);
856
    t=r;
857
  } else if (v == VT_JMP || v == VT_JMPI) {
858
    if ((v & 1) == inv) {
859
      if(!vtop->c.i)
860
	vtop->c.i=t;
861
      else {
862
	unsigned long *x;
863
	int p,lp;
864
	if(t) {
865
          p = vtop->c.i;
866
          do {
867
	    p = decbranch(lp=p);
868
          } while(p);
869
	  x = (unsigned long *)(cur_text_section->data + lp);
870
	  *x &= 0xff000000;
871
	  *x |= encbranch(lp,t,1);
872
	}
873
	t = vtop->c.i;
874
      }
875
    } else {
876
      t = gjmp(t);
877
      gsym(vtop->c.i);
878
    }
879
  } else {
880
    if (is_float(vtop->type.t)) {
881
      r=gv(RC_FLOAT);
882
      o(0xEE90F118|fpr(r)<<16);
883
      vtop->r = VT_CMP;
884
      vtop->c.i = TOK_NE;
885
      return gtst(inv, t);
886
    } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
887
      /* constant jmp optimization */
888
      if ((vtop->c.i != 0) != inv)
889
	t = gjmp(t);
890
    } else {
891
      v = gv(RC_INT);
892
      o(0xE3300000|(intr(v)<<16));
893
      vtop->r = VT_CMP;
894
      vtop->c.i = TOK_NE;
895
      return gtst(inv, t);
896
    }
897
  }
898
  vtop--;
899
  return t;
900
}
901
 
902
/* generate an integer binary operation */
903
void gen_opi(int op)
904
{
905
  int c, func = 0;
906
  unsigned long opc = 0,r,fr;
907
 
908
  c=0;
909
  switch(op) {
910
    case '+':
911
      opc = 0x8;
912
      c=1;
913
      break;
914
    case TOK_ADDC1: /* add with carry generation */
915
      opc = 0x9;
916
      c=1;
917
      break;
918
    case '-':
919
      opc = 0x4;
920
      c=1;
921
      break;
922
    case TOK_SUBC1: /* sub with carry generation */
923
      opc = 0x5;
924
      c=1;
925
      break;
926
    case TOK_ADDC2: /* add with carry use */
927
      opc = 0xA;
928
      c=1;
929
      break;
930
    case TOK_SUBC2: /* sub with carry use */
931
      opc = 0xC;
932
      c=1;
933
      break;
934
    case '&':
935
      opc = 0x0;
936
      c=1;
937
      break;
938
    case '^':
939
      opc = 0x2;
940
      c=1;
941
      break;
942
    case '|':
943
      opc = 0x18;
944
      c=1;
945
      break;
946
    case '*':
947
      gv2(RC_INT, RC_INT);
948
      r = vtop[-1].r;
949
      fr = vtop[0].r;
950
      vtop--;
951
      o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr));
952
      return;
953
    case TOK_SHL:
954
      opc = 0;
955
      c=2;
956
      break;
957
    case TOK_SHR:
958
      opc = 1;
959
      c=2;
960
      break;
961
    case TOK_SAR:
962
      opc = 2;
963
      c=2;
964
      break;
965
    case '/':
966
    case TOK_PDIV:
967
      func=TOK___divsi3;
968
      c=3;
969
      break;
970
    case TOK_UDIV:
971
      func=TOK___udivsi3;
972
      c=3;
973
      break;
974
    case '%':
975
      func=TOK___modsi3;
976
      c=3;
977
      break;
978
    case TOK_UMOD:
979
      func=TOK___umodsi3;
980
      c=3;
981
      break;
982
    case TOK_UMULL:
983
      gv2(RC_INT, RC_INT);
984
      r=intr(vtop[-1].r2=get_reg(RC_INT));
985
      c=vtop[-1].r;
986
      vtop[-1].r=get_reg_ex(RC_INT,regmask(c));
987
      vtop--;
988
      o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r));
989
      return;
990
    default:
991
      opc = 0x15;
992
      c=1;
993
      break;
994
  }
995
  switch(c) {
996
    case 1:
997
      if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
998
	if(opc == 4 || opc == 5 || opc == 0xc) {
999
	  vswap();
1000
	  opc|=2; // sub -> rsb
1001
	}
1002
      }
1003
      if ((vtop->r & VT_VALMASK) == VT_CMP ||
1004
          (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1005
        gv(RC_INT);
1006
      vswap();
1007
      c=intr(gv(RC_INT));
1008
      vswap();
1009
      opc=0xE0000000|(opc<<20)|(c<<16);
1010
      if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1011
	unsigned long x;
1012
	x=stuff_const(opc|0x2000000,vtop->c.i);
1013
	if(x) {
1014
	  r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1015
	  o(x|(r<<12));
1016
	  goto done;
1017
	}
1018
      }
1019
      fr=intr(gv(RC_INT));
1020
      r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1021
      o(opc|(r<<12)|fr);
1022
done:
1023
      vtop--;
1024
      if (op >= TOK_ULT && op <= TOK_GT) {
1025
        vtop->r = VT_CMP;
1026
        vtop->c.i = op;
1027
      }
1028
      break;
1029
    case 2:
1030
      opc=0xE1A00000|(opc<<5);
1031
      if ((vtop->r & VT_VALMASK) == VT_CMP ||
1032
          (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1033
        gv(RC_INT);
1034
      vswap();
1035
      r=intr(gv(RC_INT));
1036
      vswap();
1037
      opc|=r;
1038
      if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1039
	fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1040
	c = vtop->c.i & 0x1f;
1041
	o(opc|(c<<7)|(fr<<12));
1042
      } else {
1043
        fr=intr(gv(RC_INT));
1044
	c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1045
	o(opc|(c<<12)|(fr<<8)|0x10);
1046
      }
1047
      vtop--;
1048
      break;
1049
    case 3:
1050
      vpush_global_sym(&func_old_type, func);
1051
      vrott(3);
1052
      gfunc_call(2);
1053
      vpushi(0);
1054
      vtop->r = REG_IRET;
1055
      break;
1056
    default:
1057
      error("gen_opi %i unimplemented!",op);
1058
  }
1059
}
1060
 
1061
static int is_fconst()
1062
{
1063
  long double f;
1064
  int r;
1065
  if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
1066
    return 0;
1067
  if (vtop->type.t == VT_FLOAT)
1068
    f = vtop->c.f;
1069
  else if (vtop->type.t == VT_DOUBLE)
1070
    f = vtop->c.d;
1071
  else
1072
    f = vtop->c.ld;
1073
  if(!ieee_finite(f))
1074
    return 0;
1075
  r=0x8;
1076
  if(f<0.0) {
1077
    r=0x18;
1078
    f=-f;
1079
  }
1080
  if(f==0.0)
1081
    return r;
1082
  if(f==1.0)
1083
    return r|1;
1084
  if(f==2.0)
1085
    return r|2;
1086
  if(f==3.0)
1087
    return r|3;
1088
  if(f==4.0)
1089
    return r|4;
1090
  if(f==5.0)
1091
    return r|5;
1092
  if(f==0.5)
1093
    return r|6;
1094
  if(f==10.0)
1095
    return r|7;
1096
  return 0;
1097
}
1098
 
1099
/* generate a floating point operation 'v = t1 op t2' instruction. The
1100
   two operands are guaranted to have the same floating point type */
1101
void gen_opf(int op)
1102
{
1103
  unsigned long x;
1104
  int r,r2,c1,c2;
1105
  //fputs("gen_opf\n",stderr);
1106
  vswap();
1107
  c1 = is_fconst();
1108
  vswap();
1109
  c2 = is_fconst();
1110
  x=0xEE000100;
1111
#if LDOUBLE_SIZE == 8
1112
  if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
1113
    x|=0x80;
1114
#else
1115
  if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
1116
    x|=0x80;
1117
  else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
1118
    x|=0x80000;
1119
#endif
1120
  switch(op)
1121
  {
1122
    case '+':
1123
      if(!c2) {
1124
	vswap();
1125
	c2=c1;
1126
      }
1127
      vswap();
1128
      r=fpr(gv(RC_FLOAT));
1129
      vswap();
1130
      if(c2) {
1131
	if(c2>0xf)
1132
	  x|=0x200000; // suf
1133
	r2=c2&0xf;
1134
      } else {
1135
	r2=fpr(gv(RC_FLOAT));
1136
      }
1137
      break;
1138
    case '-':
1139
      if(c2) {
1140
	if(c2<=0xf)
1141
	  x|=0x200000; // suf
1142
	r2=c2&0xf;
1143
	vswap();
1144
	r=fpr(gv(RC_FLOAT));
1145
	vswap();
1146
      } else if(c1 && c1<=0xf) {
1147
	x|=0x300000; // rsf
1148
	r2=c1;
1149
	r=fpr(gv(RC_FLOAT));
1150
	vswap();
1151
      } else {
1152
	x|=0x200000; // suf
1153
	vswap();
1154
	r=fpr(gv(RC_FLOAT));
1155
	vswap();
1156
	r2=fpr(gv(RC_FLOAT));
1157
      }
1158
      break;
1159
    case '*':
1160
      if(!c2 || c2>0xf) {
1161
	vswap();
1162
	c2=c1;
1163
      }
1164
      vswap();
1165
      r=fpr(gv(RC_FLOAT));
1166
      vswap();
1167
      if(c2 && c2<=0xf)
1168
	r2=c2;
1169
      else
1170
	r2=fpr(gv(RC_FLOAT));
1171
      x|=0x100000; // muf
1172
      break;
1173
    case '/':
1174
      if(c2 && c2<=0xf) {
1175
	x|=0x400000; // dvf
1176
	r2=c2;
1177
	vswap();
1178
	r=fpr(gv(RC_FLOAT));
1179
	vswap();
1180
      } else if(c1 && c1<=0xf) {
1181
	x|=0x500000; // rdf
1182
	r2=c1;
1183
	r=fpr(gv(RC_FLOAT));
1184
	vswap();
1185
      } else {
1186
	x|=0x400000; // dvf
1187
	vswap();
1188
	r=fpr(gv(RC_FLOAT));
1189
	vswap();
1190
	r2=fpr(gv(RC_FLOAT));
1191
      }
1192
      break;
1193
    default:
1194
      if(op >= TOK_ULT && op <= TOK_GT) {
1195
	x|=0xd0f110; // cmfe
1196
	switch(op) {
1197
	  case TOK_ULT:
1198
	  case TOK_UGE:
1199
	  case TOK_ULE:
1200
	  case TOK_UGT:
1201
	    fputs("unsigned comparision on floats?\n",stderr);
1202
	    break;
1203
	  case TOK_LT:
1204
	    op=TOK_ULT;
1205
	    break;
1206
	  case TOK_GE:
1207
	    op=TOK_UGE;
1208
	    break;
1209
	  case TOK_LE:
1210
	    op=TOK_ULE;
1211
	    break;
1212
	  case TOK_GT:
1213
	    op=TOK_UGT;
1214
	    break;
1215
	  case TOK_EQ:
1216
	  case TOK_NE:
1217
	    x&=~0x400000; // cmfe -> cmf
1218
	    break;
1219
	}
1220
	if(c1 && !c2) {
1221
	  c2=c1;
1222
	  vswap();
1223
	  switch(op) {
1224
	    case TOK_ULT:
1225
	      op=TOK_UGT;
1226
	      break;
1227
	    case TOK_UGE:
1228
	      op=TOK_ULE;
1229
	      break;
1230
	    case TOK_ULE:
1231
	      op=TOK_UGE;
1232
	      break;
1233
	    case TOK_UGT:
1234
	      op=TOK_ULT;
1235
	      break;
1236
	  }
1237
	}
1238
// bug (intention?) in Linux FPU emulator
1239
// doesn't set carry if equal
1240
	if(op==TOK_ULT)
1241
	  op=TOK_LT;
1242
	else if(op==TOK_UGE)
1243
	  op=TOK_GE;
1244
	vswap();
1245
	r=fpr(gv(RC_FLOAT));
1246
	vswap();
1247
	if(c2) {
1248
	  if(c2>0xf)
1249
	    x|=0x200000;
1250
	  r2=c2&0xf;
1251
	} else {
1252
	  r2=fpr(gv(RC_FLOAT));
1253
	}
1254
	vtop[-1].r = VT_CMP;
1255
	vtop[-1].c.i = op;
1256
      } else {
1257
	error("unknown fp op %x!\n",op);
1258
	return;
1259
      }
1260
  }
1261
  if(vtop[-1].r == VT_CMP)
1262
    c1=15;
1263
  else {
1264
    c1=vtop->r;
1265
    if(r2&0x8)
1266
      c1=vtop[-1].r;
1267
    vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1));
1268
    c1=fpr(vtop[-1].r);
1269
  }
1270
  vtop--;
1271
  o(x|(r<<16)|(c1<<12)|r2);
1272
}
1273
 
1274
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1275
   and 'long long' cases. */
1276
void gen_cvt_itof(int t)
1277
{
1278
  int r,r2,bt;
1279
  bt=vtop->type.t & VT_BTYPE;
1280
  if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) {
1281
    r=intr(gv(RC_INT));
1282
    r2=fpr(vtop->r=get_reg(RC_FLOAT));
1283
    o(0xEE000190|(r2<<16)|(r<<12));
1284
    if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) {
1285
      unsigned int off=0;
1286
      o(0xE3500000|(r<<12));
1287
      r=fpr(get_reg(RC_FLOAT));
1288
      if(last_itod_magic) {
1289
	off=ind+8-last_itod_magic;
1290
	off/=4;
1291
	if(off>255)
1292
	  off=0;
1293
      }
1294
      o(0xBD1F8100|(r<<12)|off);
1295
      if(!off) {
1296
        o(0xEA000001);
1297
        last_itod_magic=ind;
1298
        o(0x41F00000);
1299
        o(0);
1300
      }
1301
      o(0xBE000180|(r2<<16)|(r2<<12)|r);
1302
    }
1303
    return;
1304
  } else if(bt == VT_LLONG) {
1305
    int func;
1306
    if(vtop->type.t & VT_UNSIGNED)
1307
      func=TOK___ulltold;
1308
    else
1309
      func=TOK___slltold;
1310
    vpush_global_sym(&func_old_type, func);
1311
    vswap();
1312
    gfunc_call(1);
1313
    vpushi(0);
1314
    vtop->r=TREG_F0;
1315
    return;
1316
  }
1317
  error("unimplemented gen_cvt_itof %x!",vtop->type.t);
1318
}
1319
 
1320
/* convert fp to int 't' type */
1321
void gen_cvt_ftoi(int t)
1322
{
1323
  int r,r2,u,func=0;
1324
  u=t&VT_UNSIGNED;
1325
  t&=VT_BTYPE;
1326
  r2=vtop->type.t & VT_BTYPE;
1327
  if(t==VT_INT) {
1328
    if(u) {
1329
      if(r2 == VT_FLOAT)
1330
        func=TOK___fixunssfsi;
1331
      else if(r2 == VT_DOUBLE)
1332
	func=TOK___fixunsdfsi;
1333
      else if(r2 == VT_LDOUBLE)
1334
#if LDOUBLE_SIZE == 8
1335
	func=TOK___fixunsdfsi;
1336
#else
1337
	func=TOK___fixunsxfsi;
1338
#endif
1339
    } else {
1340
      r=fpr(gv(RC_FLOAT));
1341
      r2=intr(vtop->r=get_reg(RC_INT));
1342
      o(0xEE100170|(r2<<12)|r);
1343
    return;
1344
    }
1345
  } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
1346
    if(r2 == VT_FLOAT)
1347
      func=TOK___fixsfdi;
1348
    else if(r2 == VT_DOUBLE)
1349
      func=TOK___fixdfdi;
1350
    else if(r2 == VT_LDOUBLE)
1351
#if LDOUBLE_SIZE == 8
1352
      func=TOK___fixdfdi;
1353
#else
1354
      func=TOK___fixxfdi;
1355
#endif
1356
    }
1357
  if(func) {
1358
    vpush_global_sym(&func_old_type, func);
1359
    vswap();
1360
    gfunc_call(1);
1361
    vpushi(0);
1362
    if(t == VT_LLONG)
1363
      vtop->r2 = REG_LRET;
1364
    vtop->r = REG_IRET;
1365
    return;
1366
  }
1367
  error("unimplemented gen_cvt_ftoi!");
1368
}
1369
 
1370
/* convert from one floating point type to another */
1371
void gen_cvt_ftof(int t)
1372
{
1373
  /* all we have to do on i386 and ARM is to put the float in a register */
1374
  gv(RC_FLOAT);
1375
}
1376
 
1377
/* computed goto support */
1378
void ggoto(void)
1379
{
1380
  gcall_or_jmp(1);
1381
  vtop--;
1382
}
1383
 
1384
/* end of ARM code generator */
1385
/*************************************************************/
1386