~john-koepi/ubuntu/trusty/golang/default

« back to all changes in this revision

Viewing changes to src/cmd/5l/noop.c

  • Committer: Bazaar Package Importer
  • Author(s): Ondřej Surý
  • Date: 2011-04-20 17:36:48 UTC
  • Revision ID: james.westby@ubuntu.com-20110420173648-ifergoxyrm832trd
Tags: upstream-2011.03.07.1
Import upstream version 2011.03.07.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Inferno utils/5l/noop.c
 
2
// http://code.google.com/p/inferno-os/source/browse/utils/5l/noop.c
 
3
//
 
4
//      Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
 
5
//      Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
 
6
//      Portions Copyright © 1997-1999 Vita Nuova Limited
 
7
//      Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
 
8
//      Portions Copyright © 2004,2006 Bruce Ellis
 
9
//      Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
 
10
//      Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
 
11
//      Portions Copyright © 2009 The Go Authors.  All rights reserved.
 
12
//
 
13
// Permission is hereby granted, free of charge, to any person obtaining a copy
 
14
// of this software and associated documentation files (the "Software"), to deal
 
15
// in the Software without restriction, including without limitation the rights
 
16
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
17
// copies of the Software, and to permit persons to whom the Software is
 
18
// furnished to do so, subject to the following conditions:
 
19
//
 
20
// The above copyright notice and this permission notice shall be included in
 
21
// all copies or substantial portions of the Software.
 
22
//
 
23
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
24
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
25
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 
26
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
27
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
28
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
29
// THE SOFTWARE.
 
30
 
 
31
// Code transformations.
 
32
 
 
33
#include        "l.h"
 
34
#include        "../ld/lib.h"
 
35
 
 
36
// see ../../runtime/proc.c:/StackGuard
 
37
enum
 
38
{
 
39
        StackBig = 4096,
 
40
        StackSmall = 128,
 
41
};
 
42
 
 
43
static  Sym*    sym_div;
 
44
static  Sym*    sym_divu;
 
45
static  Sym*    sym_mod;
 
46
static  Sym*    sym_modu;
 
47
 
 
48
static void setdiv(int);
 
49
 
 
50
static Prog *
 
51
movrr(Prog *q, int rs, int rd, Prog *p)
 
52
{
 
53
        if(q == nil)
 
54
                q = prg();
 
55
        q->as = AMOVW;
 
56
        q->line = p->line;
 
57
        q->from.type = D_REG;
 
58
        q->from.reg = rs;
 
59
        q->to.type = D_REG;
 
60
        q->to.reg = rd;
 
61
        q->link = p->link;
 
62
        return q;
 
63
}
 
64
 
 
65
static Prog *
 
66
fnret(Prog *q, int rs, int foreign, Prog *p)
 
67
{
 
68
        q = movrr(q, rs, REGPC, p);
 
69
        if(foreign){    // BX rs
 
70
                q->as = ABXRET;
 
71
                q->from.type = D_NONE;
 
72
                q->from.reg = NREG;
 
73
                q->to.reg = rs;
 
74
        }
 
75
        return q;
 
76
}
 
77
 
 
78
static Prog *
 
79
aword(int32 w, Prog *p)
 
80
{
 
81
        Prog *q;
 
82
 
 
83
        q = prg();
 
84
        q->as = AWORD;
 
85
        q->line = p->line;
 
86
        q->from.type = D_NONE;
 
87
        q->reg = NREG;
 
88
        q->to.type = D_CONST;
 
89
        q->to.offset = w;
 
90
        q->link = p->link;
 
91
        p->link = q;
 
92
        return q;
 
93
}
 
94
 
 
95
static Prog *
 
96
adword(int32 w1, int32 w2, Prog *p)
 
97
{
 
98
        Prog *q;
 
99
 
 
100
        q = prg();
 
101
        q->as = ADWORD;
 
102
        q->line = p->line;
 
103
        q->from.type = D_CONST;
 
104
        q->from.offset = w1;
 
105
        q->reg = NREG;
 
106
        q->to.type = D_CONST;
 
107
        q->to.offset = w2;
 
108
        q->link = p->link;
 
109
        p->link = q;
 
110
        return q;
 
111
}
 
112
 
 
113
void
 
114
noops(void)
 
115
{
 
116
        Prog *p, *q, *q1, *q2;
 
117
        int o, foreign;
 
118
        Prog *pmorestack;
 
119
        Sym *symmorestack;
 
120
 
 
121
        /*
 
122
         * find leaf subroutines
 
123
         * strip NOPs
 
124
         * expand RET
 
125
         * expand BECOME pseudo
 
126
         */
 
127
 
 
128
        if(debug['v'])
 
129
                Bprint(&bso, "%5.2f noops\n", cputime());
 
130
        Bflush(&bso);
 
131
 
 
132
        symmorestack = lookup("runtime.morestack", 0);
 
133
        if(symmorestack->type != STEXT) {
 
134
                diag("runtime·morestack not defined");
 
135
                errorexit();
 
136
        }
 
137
        pmorestack = symmorestack->text;
 
138
        pmorestack->reg |= NOSPLIT;
 
139
 
 
140
        q = P;
 
141
        for(cursym = textp; cursym != nil; cursym = cursym->next) {
 
142
                for(p = cursym->text; p != P; p = p->link) {
 
143
                        setarch(p);
 
144
        
 
145
                        switch(p->as) {
 
146
                        case ATEXT:
 
147
                                p->mark |= LEAF;
 
148
                                break;
 
149
        
 
150
                        case ARET:
 
151
                                break;
 
152
        
 
153
                        case ADIV:
 
154
                        case ADIVU:
 
155
                        case AMOD:
 
156
                        case AMODU:
 
157
                                q = p;
 
158
                                if(prog_div == P)
 
159
                                        initdiv();
 
160
                                cursym->text->mark &= ~LEAF;
 
161
                                setdiv(p->as);
 
162
                                continue;
 
163
        
 
164
                        case ANOP:
 
165
                                q1 = p->link;
 
166
                                q->link = q1;           /* q is non-nop */
 
167
                                if(q1 != P)
 
168
                                        q1->mark |= p->mark;
 
169
                                continue;
 
170
        
 
171
                        case ABL:
 
172
                        case ABX:
 
173
                                cursym->text->mark &= ~LEAF;
 
174
        
 
175
                        case ABCASE:
 
176
                        case AB:
 
177
        
 
178
                        case ABEQ:
 
179
                        case ABNE:
 
180
                        case ABCS:
 
181
                        case ABHS:
 
182
                        case ABCC:
 
183
                        case ABLO:
 
184
                        case ABMI:
 
185
                        case ABPL:
 
186
                        case ABVS:
 
187
                        case ABVC:
 
188
                        case ABHI:
 
189
                        case ABLS:
 
190
                        case ABGE:
 
191
                        case ABLT:
 
192
                        case ABGT:
 
193
                        case ABLE:
 
194
                                q1 = p->cond;
 
195
                                if(q1 != P) {
 
196
                                        while(q1->as == ANOP) {
 
197
                                                q1 = q1->link;
 
198
                                                p->cond = q1;
 
199
                                        }
 
200
                                }
 
201
                                break;
 
202
                        }
 
203
                        q = p;
 
204
                }
 
205
        }
 
206
 
 
207
        for(cursym = textp; cursym != nil; cursym = cursym->next) {
 
208
                for(p = cursym->text; p != P; p = p->link) {
 
209
                        setarch(p);
 
210
                        o = p->as;
 
211
                        switch(o) {
 
212
                        case ATEXT:
 
213
                                autosize = p->to.offset + 4;
 
214
                                if(autosize <= 4)
 
215
                                if(cursym->text->mark & LEAF) {
 
216
                                        p->to.offset = -4;
 
217
                                        autosize = 0;
 
218
                                }
 
219
        
 
220
                                if(!autosize && !(cursym->text->mark & LEAF)) {
 
221
                                        if(debug['v'])
 
222
                                                Bprint(&bso, "save suppressed in: %s\n",
 
223
                                                        cursym->name);
 
224
                                        Bflush(&bso);
 
225
                                        cursym->text->mark |= LEAF;
 
226
                                }
 
227
#ifdef CALLEEBX
 
228
                                if(p->from.sym->foreign){
 
229
                                        if(thumb)
 
230
                                                // don't allow literal pool to separate these
 
231
                                                p = adword(0xe28f7001, 0xe12fff17, p); // arm add 1, pc, r7 and bx r7
 
232
                                                // p = aword(0xe12fff17, aword(0xe28f7001, p)); // arm add 1, pc, r7 and bx r7
 
233
                                        else
 
234
                                                p = aword(0x4778, p);   // thumb bx pc and 2 bytes padding
 
235
                                }
 
236
#endif
 
237
                                if(cursym->text->mark & LEAF) {
 
238
                                        cursym->leaf = 1;
 
239
                                        if(!autosize)
 
240
                                                break;
 
241
                                }
 
242
        
 
243
                                if(thumb){
 
244
                                        if(!(p->reg & NOSPLIT))
 
245
                                                diag("stack splitting not supported in thumb");
 
246
                                        if(!(cursym->text->mark & LEAF)){
 
247
                                                q = movrr(nil, REGLINK, REGTMPT-1, p);
 
248
                                                p->link = q;
 
249
                                                q1 = prg();
 
250
                                                q1->as = AMOVW;
 
251
                                                q1->line = p->line;
 
252
                                                q1->from.type = D_REG;
 
253
                                                q1->from.reg = REGTMPT-1;
 
254
                                                q1->to.type = D_OREG;
 
255
                                                q1->to.name = D_NONE;
 
256
                                                q1->to.reg = REGSP;
 
257
                                                q1->to.offset = 0;
 
258
                                                q1->link = q->link;
 
259
                                                q->link = q1;
 
260
                                        }
 
261
                                        if(autosize){
 
262
                                                q2 = prg();
 
263
                                                q2->as = ASUB;
 
264
                                                q2->line = p->line;
 
265
                                                q2->from.type = D_CONST;
 
266
                                                q2->from.offset = autosize;
 
267
                                                q2->to.type = D_REG;
 
268
                                                q2->to.reg = REGSP;
 
269
                                                q2->link = p->link;
 
270
                                                p->link = q2;
 
271
                                        }
 
272
                                        break;
 
273
                                }
 
274
        
 
275
                                if(p->reg & NOSPLIT) {
 
276
                                        q1 = prg();
 
277
                                        q1->as = AMOVW;
 
278
                                        q1->scond |= C_WBIT;
 
279
                                        q1->line = p->line;
 
280
                                        q1->from.type = D_REG;
 
281
                                        q1->from.reg = REGLINK;
 
282
                                        q1->to.type = D_OREG;
 
283
                                        q1->to.offset = -autosize;
 
284
                                        q1->to.reg = REGSP;
 
285
                                        q1->spadj = autosize;
 
286
                                        q1->link = p->link;
 
287
                                        p->link = q1;
 
288
                                } else if (autosize < StackBig) {
 
289
                                        // split stack check for small functions
 
290
                                        // MOVW                 g_stackguard(g), R1
 
291
                                        // CMP                  R1, $-autosize(SP)
 
292
                                        // MOVW.LO              $autosize, R1
 
293
                                        // MOVW.LO              $args, R2
 
294
                                        // MOVW.LO              R14, R3
 
295
                                        // BL.LO                        runtime.morestack(SB) // modifies LR
 
296
                                        // MOVW.W               R14,$-autosize(SP)
 
297
        
 
298
                                        // TODO(kaib): add more trampolines
 
299
                                        // TODO(kaib): put stackguard in register
 
300
                                        // TODO(kaib): add support for -K and underflow detection
 
301
 
 
302
                                        // MOVW                 g_stackguard(g), R1
 
303
                                        p = appendp(p);
 
304
                                        p->as = AMOVW;
 
305
                                        p->from.type = D_OREG;
 
306
                                        p->from.reg = REGG;
 
307
                                        p->to.type = D_REG;
 
308
                                        p->to.reg = 1;
 
309
                                        
 
310
                                        if(autosize < StackSmall) {     
 
311
                                                // CMP                  R1, SP
 
312
                                                p = appendp(p);
 
313
                                                p->as = ACMP;
 
314
                                                p->from.type = D_REG;
 
315
                                                p->from.reg = 1;
 
316
                                                p->reg = REGSP;
 
317
                                        } else {
 
318
                                                // MOVW         $-autosize(SP), R2
 
319
                                                // CMP  R1, R2
 
320
                                                p = appendp(p);
 
321
                                                p->as = AMOVW;
 
322
                                                p->from.type = D_CONST;
 
323
                                                p->from.reg = REGSP;
 
324
                                                p->from.offset = -autosize;
 
325
                                                p->to.type = D_REG;
 
326
                                                p->to.reg = 2;
 
327
                                                
 
328
                                                p = appendp(p);
 
329
                                                p->as = ACMP;
 
330
                                                p->from.type = D_REG;
 
331
                                                p->from.reg = 1;
 
332
                                                p->reg = 2;
 
333
                                        }
 
334
 
 
335
                                        // MOVW.LO              $autosize, R1
 
336
                                        p = appendp(p);
 
337
                                        p->as = AMOVW;
 
338
                                        p->scond = C_SCOND_LO;
 
339
                                        p->from.type = D_CONST;
 
340
                                        /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
 
341
                                        p->from.offset = autosize+160;
 
342
                                        p->to.type = D_REG;
 
343
                                        p->to.reg = 1;
 
344
        
 
345
                                        // MOVW.LO              $args, R2
 
346
                                        p = appendp(p);
 
347
                                        p->as = AMOVW;
 
348
                                        p->scond = C_SCOND_LO;
 
349
                                        p->from.type = D_CONST;
 
350
                                        p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
 
351
                                        p->to.type = D_REG;
 
352
                                        p->to.reg = 2;
 
353
        
 
354
                                        // MOVW.LO      R14, R3
 
355
                                        p = appendp(p);
 
356
                                        p->as = AMOVW;
 
357
                                        p->scond = C_SCOND_LO;
 
358
                                        p->from.type = D_REG;
 
359
                                        p->from.reg = REGLINK;
 
360
                                        p->to.type = D_REG;
 
361
                                        p->to.reg = 3;
 
362
        
 
363
                                        // BL.LO                runtime.morestack(SB) // modifies LR
 
364
                                        p = appendp(p);
 
365
                                        p->as = ABL;
 
366
                                        p->scond = C_SCOND_LO;
 
367
                                        p->to.type = D_BRANCH;
 
368
                                        p->to.sym = symmorestack;
 
369
                                        p->cond = pmorestack;
 
370
        
 
371
                                        // MOVW.W               R14,$-autosize(SP)
 
372
                                        p = appendp(p);
 
373
                                        p->as = AMOVW;
 
374
                                        p->scond |= C_WBIT;
 
375
                                        p->from.type = D_REG;
 
376
                                        p->from.reg = REGLINK;
 
377
                                        p->to.type = D_OREG;
 
378
                                        p->to.offset = -autosize;
 
379
                                        p->to.reg = REGSP;
 
380
                                        p->spadj = autosize;
 
381
                                } else { // > StackBig
 
382
                                        // MOVW         $autosize, R1
 
383
                                        // MOVW         $args, R2
 
384
                                        // MOVW         R14, R3
 
385
                                        // BL                   runtime.morestack(SB) // modifies LR
 
386
                                        // MOVW.W               R14,$-autosize(SP)
 
387
        
 
388
                                        // MOVW         $autosize, R1
 
389
                                        p = appendp(p);
 
390
                                        p->as = AMOVW;
 
391
                                        p->from.type = D_CONST;
 
392
                                        p->from.offset = autosize;
 
393
                                        p->to.type = D_REG;
 
394
                                        p->to.reg = 1;
 
395
        
 
396
                                        // MOVW         $args, R2
 
397
                                        // also need to store the extra 4 bytes.
 
398
                                        p = appendp(p);
 
399
                                        p->as = AMOVW;
 
400
                                        p->from.type = D_CONST;
 
401
                                        p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
 
402
                                        p->to.type = D_REG;
 
403
                                        p->to.reg = 2;
 
404
        
 
405
                                        // MOVW R14, R3
 
406
                                        p = appendp(p);
 
407
                                        p->as = AMOVW;
 
408
                                        p->from.type = D_REG;
 
409
                                        p->from.reg = REGLINK;
 
410
                                        p->to.type = D_REG;
 
411
                                        p->to.reg = 3;
 
412
        
 
413
                                        // BL           runtime.morestack(SB) // modifies LR
 
414
                                        p = appendp(p);
 
415
                                        p->as = ABL;
 
416
                                        p->to.type = D_BRANCH;
 
417
                                        p->to.sym = symmorestack;
 
418
                                        p->cond = pmorestack;
 
419
        
 
420
                                        // MOVW.W               R14,$-autosize(SP)
 
421
                                        p = appendp(p);
 
422
                                        p->as = AMOVW;
 
423
                                        p->scond |= C_WBIT;
 
424
                                        p->from.type = D_REG;
 
425
                                        p->from.reg = REGLINK;
 
426
                                        p->to.type = D_OREG;
 
427
                                        p->to.offset = -autosize;
 
428
                                        p->to.reg = REGSP;
 
429
                                        p->spadj = autosize;
 
430
                                }
 
431
                                break;
 
432
        
 
433
                        case ARET:
 
434
                                nocache(p);
 
435
                                foreign = seenthumb && (cursym->foreign || cursym->fnptr);
 
436
// print("%s %d %d\n", cursym->name, cursym->foreign, cursym->fnptr);
 
437
                                if(cursym->text->mark & LEAF) {
 
438
                                        if(!autosize) {
 
439
                                                if(thumb){
 
440
                                                        p = fnret(p, REGLINK, foreign, p);
 
441
                                                        break;
 
442
                                                }
 
443
// if(foreign) print("ABXRET 1 %s\n", cursym->name);
 
444
                                                p->as = foreign ? ABXRET : AB;
 
445
                                                p->from = zprg.from;
 
446
                                                p->to.type = D_OREG;
 
447
                                                p->to.offset = 0;
 
448
                                                p->to.reg = REGLINK;
 
449
                                                break;
 
450
                                        }
 
451
                                }
 
452
                                if(thumb){
 
453
                                        if(cursym->text->mark & LEAF){
 
454
                                                if(autosize){
 
455
                                                        p->as = AADD;
 
456
                                                        p->from.type = D_CONST;
 
457
                                                        p->from.offset = autosize;
 
458
                                                        p->to.type = D_REG;
 
459
                                                        p->to.reg = REGSP;
 
460
                                                        q = nil;
 
461
                                                }
 
462
                                                else
 
463
                                                        q = p;
 
464
                                                q = fnret(q, REGLINK, foreign, p);
 
465
                                                if(q != p)
 
466
                                                        p->link = q;
 
467
                                        }
 
468
                                        else{
 
469
                                                p->as = AMOVW;
 
470
                                                p->from.type = D_OREG;
 
471
                                                p->from.name = D_NONE;
 
472
                                                p->from.reg = REGSP;
 
473
                                                p->from.offset = 0;
 
474
                                                p->to.type = D_REG;
 
475
                                                p->to.reg = REGTMPT-1;
 
476
                                                if(autosize){
 
477
                                                        q = prg();
 
478
                                                        q->as = AADD;
 
479
                                                        q->from.type = D_CONST;
 
480
                                                        q->from.offset = autosize;
 
481
                                                        q->to.type = D_REG;
 
482
                                                        q->to.reg = REGSP;
 
483
                                                        q->link = p->link;
 
484
                                                        p->link =       q;
 
485
                                                }
 
486
                                                else
 
487
                                                        q = p;
 
488
                                                q1 = fnret(nil, REGTMPT-1, foreign, p);
 
489
                                                q1->link = q->link;
 
490
                                                q->link = q1;
 
491
                                        }
 
492
                                        break;
 
493
                                }
 
494
                                if(foreign) {
 
495
// if(foreign) print("ABXRET 3 %s\n", cursym->name);
 
496
#define R       1
 
497
                                        p->as = AMOVW;
 
498
                                        p->from.type = D_OREG;
 
499
                                        p->from.name = D_NONE;
 
500
                                        p->from.reg = REGSP;
 
501
                                        p->from.offset = 0;
 
502
                                        p->to.type = D_REG;
 
503
                                        p->to.reg = R;
 
504
                                        q = prg();
 
505
                                        q->as = AADD;
 
506
                                        q->scond = p->scond;
 
507
                                        q->line = p->line;
 
508
                                        q->from.type = D_CONST;
 
509
                                        q->from.offset = autosize;
 
510
                                        q->to.type = D_REG;
 
511
                                        q->to.reg = REGSP;
 
512
                                        q->link = p->link;
 
513
                                        p->link = q;
 
514
                                        q1 = prg();
 
515
                                        q1->as = ABXRET;
 
516
                                        q1->scond = p->scond;
 
517
                                        q1->line = p->line;
 
518
                                        q1->to.type = D_OREG;
 
519
                                        q1->to.offset = 0;
 
520
                                        q1->to.reg = R;
 
521
                                        q1->link = q->link;
 
522
                                        q->link = q1;
 
523
#undef  R
 
524
                                }
 
525
                                else {
 
526
                                        p->as = AMOVW;
 
527
                                        p->scond |= C_PBIT;
 
528
                                        p->from.type = D_OREG;
 
529
                                        p->from.offset = autosize;
 
530
                                        p->from.reg = REGSP;
 
531
                                        p->to.type = D_REG;
 
532
                                        p->to.reg = REGPC;
 
533
                                        // no spadj because it doesn't fall through
 
534
                                }
 
535
                                break;
 
536
        
 
537
                        case AADD:
 
538
                                if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
 
539
                                        p->spadj = -p->from.offset;
 
540
                                break;
 
541
 
 
542
                        case ASUB:
 
543
                                if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
 
544
                                        p->spadj = p->from.offset;
 
545
                                break;
 
546
 
 
547
                        case ADIV:
 
548
                        case ADIVU:
 
549
                        case AMOD:
 
550
                        case AMODU:
 
551
                                if(debug['M'])
 
552
                                        break;
 
553
                                if(p->from.type != D_REG)
 
554
                                        break;
 
555
                                if(p->to.type != D_REG)
 
556
                                        break;
 
557
                                q1 = p;
 
558
        
 
559
                                /* MOV a,4(SP) */
 
560
                                q = prg();
 
561
                                q->link = p->link;
 
562
                                p->link = q;
 
563
                                p = q;
 
564
        
 
565
                                p->as = AMOVW;
 
566
                                p->line = q1->line;
 
567
                                p->from.type = D_REG;
 
568
                                p->from.reg = q1->from.reg;
 
569
                                p->to.type = D_OREG;
 
570
                                p->to.reg = REGSP;
 
571
                                p->to.offset = 4;
 
572
        
 
573
                                /* MOV b,REGTMP */
 
574
                                q = prg();
 
575
                                q->link = p->link;
 
576
                                p->link = q;
 
577
                                p = q;
 
578
        
 
579
                                p->as = AMOVW;
 
580
                                p->line = q1->line;
 
581
                                p->from.type = D_REG;
 
582
                                p->from.reg = q1->reg;
 
583
                                if(q1->reg == NREG)
 
584
                                        p->from.reg = q1->to.reg;
 
585
                                p->to.type = D_REG;
 
586
                                p->to.reg = prog_div->from.sym->thumb ? REGTMPT : REGTMP;
 
587
                                p->to.offset = 0;
 
588
        
 
589
                                /* CALL appropriate */
 
590
                                q = prg();
 
591
                                q->link = p->link;
 
592
                                p->link = q;
 
593
                                p = q;
 
594
        
 
595
#ifdef CALLEEBX
 
596
                                p->as = ABL;
 
597
#else
 
598
                                if(prog_div->from.sym->thumb)
 
599
                                        p->as = thumb ? ABL : ABX;
 
600
                                else
 
601
                                        p->as = thumb ? ABX : ABL;
 
602
#endif
 
603
                                p->line = q1->line;
 
604
                                p->to.type = D_BRANCH;
 
605
                                p->cond = p;
 
606
                                switch(o) {
 
607
                                case ADIV:
 
608
                                        p->cond = prog_div;
 
609
                                        p->to.sym = sym_div;
 
610
                                        break;
 
611
                                case ADIVU:
 
612
                                        p->cond = prog_divu;
 
613
                                        p->to.sym = sym_divu;
 
614
                                        break;
 
615
                                case AMOD:
 
616
                                        p->cond = prog_mod;
 
617
                                        p->to.sym = sym_mod;
 
618
                                        break;
 
619
                                case AMODU:
 
620
                                        p->cond = prog_modu;
 
621
                                        p->to.sym = sym_modu;
 
622
                                        break;
 
623
                                }
 
624
        
 
625
                                /* MOV REGTMP, b */
 
626
                                q = prg();
 
627
                                q->link = p->link;
 
628
                                p->link = q;
 
629
                                p = q;
 
630
        
 
631
                                p->as = AMOVW;
 
632
                                p->line = q1->line;
 
633
                                p->from.type = D_REG;
 
634
                                p->from.reg = prog_div->from.sym->thumb ? REGTMPT : REGTMP;
 
635
                                p->from.offset = 0;
 
636
                                p->to.type = D_REG;
 
637
                                p->to.reg = q1->to.reg;
 
638
        
 
639
                                /* ADD $8,SP */
 
640
                                q = prg();
 
641
                                q->link = p->link;
 
642
                                p->link = q;
 
643
                                p = q;
 
644
        
 
645
                                p->as = AADD;
 
646
                                p->from.type = D_CONST;
 
647
                                p->from.reg = NREG;
 
648
                                p->from.offset = 8;
 
649
                                p->reg = NREG;
 
650
                                p->to.type = D_REG;
 
651
                                p->to.reg = REGSP;
 
652
                                p->spadj = -8;
 
653
        
 
654
                                /* SUB $8,SP */
 
655
                                q1->as = ASUB;
 
656
                                q1->from.type = D_CONST;
 
657
                                q1->from.offset = 8;
 
658
                                q1->from.reg = NREG;
 
659
                                q1->reg = NREG;
 
660
                                q1->to.type = D_REG;
 
661
                                q1->to.reg = REGSP;
 
662
                                q1->spadj = 8;
 
663
        
 
664
                                break;
 
665
                        case AMOVW:
 
666
                                if(thumb){
 
667
                                        Adr *a = &p->from;
 
668
        
 
669
                                        if(a->type == D_CONST && ((a->name == D_NONE && a->reg == REGSP) || a->name == D_AUTO || a->name == D_PARAM) && (a->offset & 3))
 
670
                                                diag("SP offset not multiple of 4");
 
671
                                }
 
672
                                if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
 
673
                                        p->spadj = -p->to.offset;
 
674
                                if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
 
675
                                        p->spadj = -p->from.offset;
 
676
                                if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
 
677
                                        p->spadj = -p->from.offset;
 
678
                                break;
 
679
                        case AMOVB:
 
680
                        case AMOVBU:
 
681
                        case AMOVH:
 
682
                        case AMOVHU:
 
683
                                if(thumb){
 
684
                                        if(p->from.type == D_OREG && (p->from.name == D_AUTO || p->from.name == D_PARAM || (p->from.name == D_CONST && p->from.reg == REGSP))){
 
685
                                                q = prg();
 
686
                                                *q = *p;
 
687
                                                if(p->from.name == D_AUTO)
 
688
                                                        q->from.offset += autosize;
 
689
                                                else if(p->from.name == D_PARAM)
 
690
                                                        q->from.offset += autosize+4;
 
691
                                                q->from.name = D_NONE;
 
692
                                                q->from.reg = REGTMPT;
 
693
                                                p = movrr(p, REGSP, REGTMPT, p);
 
694
                                                q->link = p->link;
 
695
                                                p->link = q;
 
696
                                        }
 
697
                                        if(p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM || (p->to.name == D_CONST && p->to.reg == REGSP))){
 
698
                                                q = prg();
 
699
                                                *q = *p;
 
700
                                                if(p->to.name == D_AUTO)
 
701
                                                        q->to.offset += autosize;
 
702
                                                else if(p->to.name == D_PARAM)
 
703
                                                        q->to.offset += autosize+4;
 
704
                                                q->to.name = D_NONE;
 
705
                                                q->to.reg = REGTMPT;
 
706
                                                p = movrr(p, REGSP, REGTMPT, p);
 
707
                                                q->link = p->link;
 
708
                                                p->link = q;
 
709
                                                if(q->to.offset < 0 || q->to.offset > 255){     // complicated
 
710
                                                        p->to.reg = REGTMPT+1;                  // mov sp, r8
 
711
                                                        q1 = prg();
 
712
                                                        q1->line = p->line;
 
713
                                                        q1->as = AMOVW;
 
714
                                                        q1->from.type = D_CONST;
 
715
                                                        q1->from.offset = q->to.offset;
 
716
                                                        q1->to.type = D_REG;
 
717
                                                        q1->to.reg = REGTMPT;                   // mov $o, r7
 
718
                                                        p->link = q1;
 
719
                                                        q1->link = q;
 
720
                                                        q1 = prg();
 
721
                                                        q1->line = p->line;
 
722
                                                        q1->as = AADD;
 
723
                                                        q1->from.type = D_REG;
 
724
                                                        q1->from.reg = REGTMPT+1;
 
725
                                                        q1->to.type = D_REG;
 
726
                                                        q1->to.reg = REGTMPT;                   // add r8, r7
 
727
                                                        p->link->link = q1;
 
728
                                                        q1->link = q;
 
729
                                                        q->to.offset = 0;                               // mov* r, 0(r7)
 
730
                                                        /* phew */
 
731
                                                }
 
732
                                        }
 
733
                                }
 
734
                                break;
 
735
                        case AMOVM:
 
736
                                if(thumb){
 
737
                                        if(p->from.type == D_OREG){
 
738
                                                if(p->from.offset == 0)
 
739
                                                        p->from.type = D_REG;
 
740
                                                else
 
741
                                                        diag("non-zero AMOVM offset");
 
742
                                        }
 
743
                                        else if(p->to.type == D_OREG){
 
744
                                                if(p->to.offset == 0)
 
745
                                                        p->to.type = D_REG;
 
746
                                                else
 
747
                                                        diag("non-zero AMOVM offset");
 
748
                                        }
 
749
                                }
 
750
                                break;
 
751
                        case AB:
 
752
                                if(thumb && p->to.type == D_OREG){
 
753
                                        if(p->to.offset == 0){
 
754
                                                p->as = AMOVW;
 
755
                                                p->from.type = D_REG;
 
756
                                                p->from.reg = p->to.reg;
 
757
                                                p->to.type = D_REG;
 
758
                                                p->to.reg = REGPC;
 
759
                                        }
 
760
                                        else{
 
761
                                                p->as = AADD;
 
762
                                                p->from.type = D_CONST;
 
763
                                                p->from.offset = p->to.offset;
 
764
                                                p->reg = p->to.reg;
 
765
                                                p->to.type = D_REG;
 
766
                                                p->to.reg = REGTMPT-1;
 
767
                                                q = prg();
 
768
                                                q->as = AMOVW;
 
769
                                                q->line = p->line;
 
770
                                                q->from.type = D_REG;
 
771
                                                q->from.reg = REGTMPT-1;
 
772
                                                q->to.type = D_REG;
 
773
                                                q->to.reg = REGPC;
 
774
                                                q->link = p->link;
 
775
                                                p->link = q;
 
776
                                        }
 
777
                                }
 
778
                                if(seenthumb && !thumb && p->to.type == D_OREG && p->to.reg == REGLINK){
 
779
                                        // print("warn %s:      b       (R%d)   assuming a return\n", cursym->name, p->to.reg);
 
780
                                        p->as = ABXRET;
 
781
                                }
 
782
                                break;
 
783
                        case ABL:
 
784
                        case ABX:
 
785
                                if(thumb && p->to.type == D_OREG){
 
786
                                        if(p->to.offset == 0){
 
787
                                                p->as = o;
 
788
                                                p->from.type = D_NONE;
 
789
                                                p->to.type = D_REG;
 
790
                                        }
 
791
                                        else{
 
792
                                                p->as = AADD;
 
793
                                                p->from.type = D_CONST;
 
794
                                                p->from.offset = p->to.offset;
 
795
                                                p->reg = p->to.reg;
 
796
                                                p->to.type = D_REG;
 
797
                                                p->to.reg = REGTMPT-1;
 
798
                                                q = prg();
 
799
                                                q->as = o;
 
800
                                                q->line = p->line;
 
801
                                                q->from.type = D_NONE;
 
802
                                                q->to.type = D_REG;
 
803
                                                q->to.reg = REGTMPT-1;
 
804
                                                q->link = p->link;
 
805
                                                p->link = q;
 
806
                                        }
 
807
                                }
 
808
                                break;
 
809
                        }
 
810
                }
 
811
        }
 
812
}
 
813
 
 
814
static void
 
815
sigdiv(char *n)
 
816
{
 
817
        Sym *s;
 
818
 
 
819
        s = lookup(n, 0);
 
820
        if(s->type == STEXT)
 
821
                if(s->sig == 0)
 
822
                        s->sig = SIGNINTERN;
 
823
}
 
824
 
 
825
void
 
826
divsig(void)
 
827
{
 
828
        sigdiv("_div");
 
829
        sigdiv("_divu");
 
830
        sigdiv("_mod");
 
831
        sigdiv("_modu");
 
832
}
 
833
 
 
834
void
 
835
initdiv(void)
 
836
{
 
837
        Sym *s2, *s3, *s4, *s5;
 
838
 
 
839
        if(prog_div != P)
 
840
                return;
 
841
        sym_div = s2 = lookup("_div", 0);
 
842
        sym_divu = s3 = lookup("_divu", 0);
 
843
        sym_mod = s4 = lookup("_mod", 0);
 
844
        sym_modu = s5 = lookup("_modu", 0);
 
845
        prog_div = s2->text;
 
846
        prog_divu = s3->text;
 
847
        prog_mod = s4->text;
 
848
        prog_modu = s5->text;
 
849
        if(prog_div == P) {
 
850
                diag("undefined: %s", s2->name);
 
851
                prog_div = cursym->text;
 
852
        }
 
853
        if(prog_divu == P) {
 
854
                diag("undefined: %s", s3->name);
 
855
                prog_divu = cursym->text;
 
856
        }
 
857
        if(prog_mod == P) {
 
858
                diag("undefined: %s", s4->name);
 
859
                prog_mod = cursym->text;
 
860
        }
 
861
        if(prog_modu == P) {
 
862
                diag("undefined: %s", s5->name);
 
863
                prog_modu = cursym->text;
 
864
        }
 
865
}
 
866
 
 
867
static void
 
868
setdiv(int as)
 
869
{
 
870
        Prog *p = nil;
 
871
 
 
872
        switch(as){
 
873
        case ADIV: p = prog_div; break;
 
874
        case ADIVU: p = prog_divu; break;
 
875
        case AMOD: p = prog_mod; break;
 
876
        case AMODU: p = prog_modu; break;
 
877
        }
 
878
        if(thumb != p->from.sym->thumb)
 
879
                p->from.sym->foreign = 1;
 
880
}
 
881
 
 
882
void
 
883
nocache(Prog *p)
 
884
{
 
885
        p->optab = 0;
 
886
        p->from.class = 0;
 
887
        p->to.class = 0;
 
888
}