]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/mips64/gsubr.go
eb1c55d7e69b2d500a50783ba66cc73b7f80d507
[gostls13.git] / src / cmd / compile / internal / mips64 / gsubr.go
1 // Derived from Inferno utils/6c/txt.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.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 package mips64
32
33 import (
34         "cmd/compile/internal/big"
35         "cmd/compile/internal/gc"
36         "cmd/internal/obj"
37         "cmd/internal/obj/mips"
38         "fmt"
39 )
40
41 var resvd = []int{
42         mips.REGZERO,
43         mips.REGSP,   // reserved for SP
44         mips.REGSB,   // reserved for SB
45         mips.REGLINK, // reserved for link
46         mips.REGG,
47         mips.REGTMP,
48         mips.REG_R26, // kernel
49         mips.REG_R27, // kernel
50         mips.FREGZERO,
51         mips.FREGHALF,
52         mips.FREGONE,
53         mips.FREGTWO,
54 }
55
56 /*
57  * generate
58  *      as $c, n
59  */
60 func ginscon(as obj.As, c int64, n2 *gc.Node) {
61         var n1 gc.Node
62
63         gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
64
65         if as != mips.AMOVV && (c < -mips.BIG || c > mips.BIG) || n2.Op != gc.OREGISTER || as == mips.AMUL || as == mips.AMULU || as == mips.AMULV || as == mips.AMULVU {
66                 // cannot have more than 16-bit of immediate in ADD, etc.
67                 // instead, MOV into register first.
68                 var ntmp gc.Node
69                 gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
70
71                 rawgins(mips.AMOVV, &n1, &ntmp)
72                 rawgins(as, &ntmp, n2)
73                 gc.Regfree(&ntmp)
74                 return
75         }
76
77         rawgins(as, &n1, n2)
78 }
79
80 // generate branch
81 // n1, n2 are registers
82 func ginsbranch(as obj.As, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
83         p := gc.Gbranch(as, t, likely)
84         gc.Naddr(&p.From, n1)
85         if n2 != nil {
86                 p.Reg = n2.Reg
87         }
88         return p
89 }
90
91 func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
92         if !t.IsFloat() && (op == gc.OLT || op == gc.OGE) {
93                 // swap nodes to fit SGT instruction
94                 n1, n2 = n2, n1
95         }
96         if t.IsFloat() && (op == gc.OLT || op == gc.OLE) {
97                 // swap nodes to fit CMPGT, CMPGE instructions and reverse relation
98                 n1, n2 = n2, n1
99                 if op == gc.OLT {
100                         op = gc.OGT
101                 } else {
102                         op = gc.OGE
103                 }
104         }
105
106         var r1, r2, g1, g2 gc.Node
107         gc.Regalloc(&r1, t, n1)
108         gc.Regalloc(&g1, n1.Type, &r1)
109         gc.Cgen(n1, &g1)
110         gmove(&g1, &r1)
111
112         gc.Regalloc(&r2, t, n2)
113         gc.Regalloc(&g2, n1.Type, &r2)
114         gc.Cgen(n2, &g2)
115         gmove(&g2, &r2)
116
117         var p *obj.Prog
118         var ntmp gc.Node
119         gc.Nodreg(&ntmp, gc.Types[gc.TINT], mips.REGTMP)
120
121         switch gc.Simtype[t.Etype] {
122         case gc.TINT8,
123                 gc.TINT16,
124                 gc.TINT32,
125                 gc.TINT64:
126                 if op == gc.OEQ || op == gc.ONE {
127                         p = ginsbranch(optoas(op, t), nil, &r1, &r2, likely)
128                 } else {
129                         gins3(mips.ASGT, &r1, &r2, &ntmp)
130
131                         p = ginsbranch(optoas(op, t), nil, &ntmp, nil, likely)
132                 }
133
134         case gc.TBOOL,
135                 gc.TUINT8,
136                 gc.TUINT16,
137                 gc.TUINT32,
138                 gc.TUINT64,
139                 gc.TPTR32,
140                 gc.TPTR64:
141                 if op == gc.OEQ || op == gc.ONE {
142                         p = ginsbranch(optoas(op, t), nil, &r1, &r2, likely)
143                 } else {
144                         gins3(mips.ASGTU, &r1, &r2, &ntmp)
145
146                         p = ginsbranch(optoas(op, t), nil, &ntmp, nil, likely)
147                 }
148
149         case gc.TFLOAT32:
150                 switch op {
151                 default:
152                         gc.Fatalf("ginscmp: no entry for op=%s type=%v", op, t)
153
154                 case gc.OEQ,
155                         gc.ONE:
156                         gins3(mips.ACMPEQF, &r1, &r2, nil)
157
158                 case gc.OGE:
159                         gins3(mips.ACMPGEF, &r1, &r2, nil)
160
161                 case gc.OGT:
162                         gins3(mips.ACMPGTF, &r1, &r2, nil)
163                 }
164                 p = gc.Gbranch(optoas(op, t), nil, likely)
165
166         case gc.TFLOAT64:
167                 switch op {
168                 default:
169                         gc.Fatalf("ginscmp: no entry for op=%s type=%v", op, t)
170
171                 case gc.OEQ,
172                         gc.ONE:
173                         gins3(mips.ACMPEQD, &r1, &r2, nil)
174
175                 case gc.OGE:
176                         gins3(mips.ACMPGED, &r1, &r2, nil)
177
178                 case gc.OGT:
179                         gins3(mips.ACMPGTD, &r1, &r2, nil)
180                 }
181                 p = gc.Gbranch(optoas(op, t), nil, likely)
182         }
183
184         gc.Regfree(&g2)
185         gc.Regfree(&r2)
186         gc.Regfree(&g1)
187         gc.Regfree(&r1)
188
189         return p
190 }
191
192 // set up nodes representing 2^63
193 var (
194         bigi         gc.Node
195         bigf         gc.Node
196         bignodes_did bool
197 )
198
199 func bignodes() {
200         if bignodes_did {
201                 return
202         }
203         bignodes_did = true
204
205         var i big.Int
206         i.SetInt64(1)
207         i.Lsh(&i, 63)
208
209         gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
210         bigi.SetBigInt(&i)
211
212         bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64])
213 }
214
215 /*
216  * generate move:
217  *      t = f
218  * hard part is conversions.
219  */
220 func gmove(f *gc.Node, t *gc.Node) {
221         if gc.Debug['M'] != 0 {
222                 fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
223         }
224
225         ft := int(gc.Simsimtype(f.Type))
226         tt := int(gc.Simsimtype(t.Type))
227         cvt := t.Type
228
229         if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
230                 gc.Complexmove(f, t)
231                 return
232         }
233
234         // cannot have two memory operands
235         var r2 gc.Node
236         var r1 gc.Node
237         var a obj.As
238         if gc.Ismem(f) && gc.Ismem(t) {
239                 goto hard
240         }
241
242         // convert constant to desired type
243         if f.Op == gc.OLITERAL {
244                 var con gc.Node
245                 switch tt {
246                 default:
247                         f.Convconst(&con, t.Type)
248
249                 case gc.TINT32,
250                         gc.TINT16,
251                         gc.TINT8:
252                         var con gc.Node
253                         f.Convconst(&con, gc.Types[gc.TINT64])
254                         var r1 gc.Node
255                         gc.Regalloc(&r1, con.Type, t)
256                         gins(mips.AMOVV, &con, &r1)
257                         gmove(&r1, t)
258                         gc.Regfree(&r1)
259                         return
260
261                 case gc.TUINT32,
262                         gc.TUINT16,
263                         gc.TUINT8:
264                         var con gc.Node
265                         f.Convconst(&con, gc.Types[gc.TUINT64])
266                         var r1 gc.Node
267                         gc.Regalloc(&r1, con.Type, t)
268                         gins(mips.AMOVV, &con, &r1)
269                         gmove(&r1, t)
270                         gc.Regfree(&r1)
271                         return
272                 }
273
274                 f = &con
275                 ft = tt // so big switch will choose a simple mov
276
277                 // constants can't move directly to memory.
278                 if gc.Ismem(t) {
279                         goto hard
280                 }
281         }
282
283         // value -> value copy, first operand in memory.
284         // any floating point operand requires register
285         // src, so goto hard to copy to register first.
286         if gc.Ismem(f) && ft != tt && (gc.Isfloat[ft] || gc.Isfloat[tt]) {
287                 cvt = gc.Types[ft]
288                 goto hard
289         }
290
291         // value -> value copy, only one memory operand.
292         // figure out the instruction to use.
293         // break out of switch for one-instruction gins.
294         // goto rdst for "destination must be register".
295         // goto hard for "convert to cvt type first".
296         // otherwise handle and return.
297
298         switch uint32(ft)<<16 | uint32(tt) {
299         default:
300                 gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
301
302                 /*
303                  * integer copy and truncate
304                  */
305         case gc.TINT8<<16 | gc.TINT8, // same size
306                 gc.TUINT8<<16 | gc.TINT8,
307                 gc.TINT16<<16 | gc.TINT8, // truncate
308                 gc.TUINT16<<16 | gc.TINT8,
309                 gc.TINT32<<16 | gc.TINT8,
310                 gc.TUINT32<<16 | gc.TINT8,
311                 gc.TINT64<<16 | gc.TINT8,
312                 gc.TUINT64<<16 | gc.TINT8:
313                 a = mips.AMOVB
314
315         case gc.TINT8<<16 | gc.TUINT8, // same size
316                 gc.TUINT8<<16 | gc.TUINT8,
317                 gc.TINT16<<16 | gc.TUINT8, // truncate
318                 gc.TUINT16<<16 | gc.TUINT8,
319                 gc.TINT32<<16 | gc.TUINT8,
320                 gc.TUINT32<<16 | gc.TUINT8,
321                 gc.TINT64<<16 | gc.TUINT8,
322                 gc.TUINT64<<16 | gc.TUINT8:
323                 a = mips.AMOVBU
324
325         case gc.TINT16<<16 | gc.TINT16, // same size
326                 gc.TUINT16<<16 | gc.TINT16,
327                 gc.TINT32<<16 | gc.TINT16, // truncate
328                 gc.TUINT32<<16 | gc.TINT16,
329                 gc.TINT64<<16 | gc.TINT16,
330                 gc.TUINT64<<16 | gc.TINT16:
331                 a = mips.AMOVH
332
333         case gc.TINT16<<16 | gc.TUINT16, // same size
334                 gc.TUINT16<<16 | gc.TUINT16,
335                 gc.TINT32<<16 | gc.TUINT16, // truncate
336                 gc.TUINT32<<16 | gc.TUINT16,
337                 gc.TINT64<<16 | gc.TUINT16,
338                 gc.TUINT64<<16 | gc.TUINT16:
339                 a = mips.AMOVHU
340
341         case gc.TINT32<<16 | gc.TINT32, // same size
342                 gc.TUINT32<<16 | gc.TINT32,
343                 gc.TINT64<<16 | gc.TINT32, // truncate
344                 gc.TUINT64<<16 | gc.TINT32:
345                 a = mips.AMOVW
346
347         case gc.TINT32<<16 | gc.TUINT32, // same size
348                 gc.TUINT32<<16 | gc.TUINT32,
349                 gc.TINT64<<16 | gc.TUINT32, // truncate
350                 gc.TUINT64<<16 | gc.TUINT32:
351                 a = mips.AMOVWU
352
353         case gc.TINT64<<16 | gc.TINT64, // same size
354                 gc.TINT64<<16 | gc.TUINT64,
355                 gc.TUINT64<<16 | gc.TINT64,
356                 gc.TUINT64<<16 | gc.TUINT64:
357                 a = mips.AMOVV
358
359                 /*
360                  * integer up-conversions
361                  */
362         case gc.TINT8<<16 | gc.TINT16, // sign extend int8
363                 gc.TINT8<<16 | gc.TUINT16,
364                 gc.TINT8<<16 | gc.TINT32,
365                 gc.TINT8<<16 | gc.TUINT32,
366                 gc.TINT8<<16 | gc.TINT64,
367                 gc.TINT8<<16 | gc.TUINT64:
368                 a = mips.AMOVB
369
370                 goto rdst
371
372         case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
373                 gc.TUINT8<<16 | gc.TUINT16,
374                 gc.TUINT8<<16 | gc.TINT32,
375                 gc.TUINT8<<16 | gc.TUINT32,
376                 gc.TUINT8<<16 | gc.TINT64,
377                 gc.TUINT8<<16 | gc.TUINT64:
378                 a = mips.AMOVBU
379
380                 goto rdst
381
382         case gc.TINT16<<16 | gc.TINT32, // sign extend int16
383                 gc.TINT16<<16 | gc.TUINT32,
384                 gc.TINT16<<16 | gc.TINT64,
385                 gc.TINT16<<16 | gc.TUINT64:
386                 a = mips.AMOVH
387
388                 goto rdst
389
390         case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
391                 gc.TUINT16<<16 | gc.TUINT32,
392                 gc.TUINT16<<16 | gc.TINT64,
393                 gc.TUINT16<<16 | gc.TUINT64:
394                 a = mips.AMOVHU
395
396                 goto rdst
397
398         case gc.TINT32<<16 | gc.TINT64, // sign extend int32
399                 gc.TINT32<<16 | gc.TUINT64:
400                 a = mips.AMOVW
401
402                 goto rdst
403
404         case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
405                 gc.TUINT32<<16 | gc.TUINT64:
406                 a = mips.AMOVWU
407
408                 goto rdst
409
410                 //warn("gmove: convert float to int not implemented: %N -> %N\n", f, t);
411         //return;
412         // algorithm is:
413         //      if small enough, use native float64 -> int64 conversion.
414         //      otherwise, subtract 2^63, convert, and add it back.
415         /*
416         * float to integer
417          */
418         case gc.TFLOAT32<<16 | gc.TINT32,
419                 gc.TFLOAT64<<16 | gc.TINT32,
420                 gc.TFLOAT32<<16 | gc.TINT64,
421                 gc.TFLOAT64<<16 | gc.TINT64,
422                 gc.TFLOAT32<<16 | gc.TINT16,
423                 gc.TFLOAT32<<16 | gc.TINT8,
424                 gc.TFLOAT32<<16 | gc.TUINT16,
425                 gc.TFLOAT32<<16 | gc.TUINT8,
426                 gc.TFLOAT64<<16 | gc.TINT16,
427                 gc.TFLOAT64<<16 | gc.TINT8,
428                 gc.TFLOAT64<<16 | gc.TUINT16,
429                 gc.TFLOAT64<<16 | gc.TUINT8,
430                 gc.TFLOAT32<<16 | gc.TUINT32,
431                 gc.TFLOAT64<<16 | gc.TUINT32,
432                 gc.TFLOAT32<<16 | gc.TUINT64,
433                 gc.TFLOAT64<<16 | gc.TUINT64:
434                 bignodes()
435
436                 gc.Regalloc(&r1, gc.Types[gc.TFLOAT64], nil)
437                 gmove(f, &r1)
438                 if tt == gc.TUINT64 {
439                         gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], nil)
440                         gmove(&bigf, &r2)
441                         gins3(mips.ACMPGED, &r1, &r2, nil)
442                         p1 := gc.Gbranch(mips.ABFPF, nil, 0)
443                         gins(mips.ASUBD, &r2, &r1)
444                         gc.Patch(p1, gc.Pc)
445                         gc.Regfree(&r2)
446                 }
447
448                 gc.Regalloc(&r2, gc.Types[gc.TINT64], t)
449                 gins(mips.ATRUNCDV, &r1, &r1)
450                 gins(mips.AMOVV, &r1, &r2)
451                 gc.Regfree(&r1)
452
453                 if tt == gc.TUINT64 {
454                         p1 := gc.Gbranch(mips.ABFPF, nil, 0) // use FCR0 here again
455                         gc.Nodreg(&r1, gc.Types[gc.TINT64], mips.REGTMP)
456                         gmove(&bigi, &r1)
457                         gins(mips.AADDVU, &r1, &r2)
458                         gc.Patch(p1, gc.Pc)
459                 }
460
461                 gmove(&r2, t)
462                 gc.Regfree(&r2)
463                 return
464
465                 //warn("gmove: convert int to float not implemented: %N -> %N\n", f, t);
466         //return;
467         // algorithm is:
468         //      if small enough, use native int64 -> float64 conversion.
469         //      otherwise, halve (rounding to odd?), convert, and double.
470         /*
471          * integer to float
472          */
473         case gc.TINT32<<16 | gc.TFLOAT32,
474                 gc.TINT32<<16 | gc.TFLOAT64,
475                 gc.TINT64<<16 | gc.TFLOAT32,
476                 gc.TINT64<<16 | gc.TFLOAT64,
477                 gc.TINT16<<16 | gc.TFLOAT32,
478                 gc.TINT16<<16 | gc.TFLOAT64,
479                 gc.TINT8<<16 | gc.TFLOAT32,
480                 gc.TINT8<<16 | gc.TFLOAT64,
481                 gc.TUINT16<<16 | gc.TFLOAT32,
482                 gc.TUINT16<<16 | gc.TFLOAT64,
483                 gc.TUINT8<<16 | gc.TFLOAT32,
484                 gc.TUINT8<<16 | gc.TFLOAT64,
485                 gc.TUINT32<<16 | gc.TFLOAT32,
486                 gc.TUINT32<<16 | gc.TFLOAT64,
487                 gc.TUINT64<<16 | gc.TFLOAT32,
488                 gc.TUINT64<<16 | gc.TFLOAT64:
489                 bignodes()
490
491                 var rtmp gc.Node
492                 gc.Regalloc(&r1, gc.Types[gc.TINT64], nil)
493                 gmove(f, &r1)
494                 if ft == gc.TUINT64 {
495                         gc.Nodreg(&rtmp, gc.Types[gc.TUINT64], mips.REGTMP)
496                         gmove(&bigi, &rtmp)
497                         gins(mips.AAND, &r1, &rtmp)
498                         p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0)
499                         p2 := gins(mips.ASRLV, nil, &r1)
500                         p2.From.Type = obj.TYPE_CONST
501                         p2.From.Offset = 1
502                         gc.Patch(p1, gc.Pc)
503                 }
504
505                 gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t)
506                 gins(mips.AMOVV, &r1, &r2)
507                 gins(mips.AMOVVD, &r2, &r2)
508                 gc.Regfree(&r1)
509
510                 if ft == gc.TUINT64 {
511                         p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0)
512                         gc.Nodreg(&r1, gc.Types[gc.TFLOAT64], mips.FREGTWO)
513                         gins(mips.AMULD, &r1, &r2)
514                         gc.Patch(p1, gc.Pc)
515                 }
516
517                 gmove(&r2, t)
518                 gc.Regfree(&r2)
519                 return
520
521                 /*
522                  * float to float
523                  */
524         case gc.TFLOAT32<<16 | gc.TFLOAT32:
525                 a = mips.AMOVF
526
527         case gc.TFLOAT64<<16 | gc.TFLOAT64:
528                 a = mips.AMOVD
529
530         case gc.TFLOAT32<<16 | gc.TFLOAT64:
531                 a = mips.AMOVFD
532                 goto rdst
533
534         case gc.TFLOAT64<<16 | gc.TFLOAT32:
535                 a = mips.AMOVDF
536                 goto rdst
537         }
538
539         gins(a, f, t)
540         return
541
542         // requires register destination
543 rdst:
544         {
545                 gc.Regalloc(&r1, t.Type, t)
546
547                 gins(a, f, &r1)
548                 gmove(&r1, t)
549                 gc.Regfree(&r1)
550                 return
551         }
552
553         // requires register intermediate
554 hard:
555         gc.Regalloc(&r1, cvt, t)
556
557         gmove(f, &r1)
558         gmove(&r1, t)
559         gc.Regfree(&r1)
560         return
561 }
562
563 // gins is called by the front end.
564 // It synthesizes some multiple-instruction sequences
565 // so the front end can stay simpler.
566 func gins(as obj.As, f, t *gc.Node) *obj.Prog {
567         if as >= obj.A_ARCHSPECIFIC {
568                 if x, ok := f.IntLiteral(); ok {
569                         ginscon(as, x, t)
570                         return nil // caller must not use
571                 }
572         }
573         return rawgins(as, f, t)
574 }
575
576 /*
577  * generate one instruction:
578  *      as f, r, t
579  * r must be register, if not nil
580  */
581 func gins3(as obj.As, f, r, t *gc.Node) *obj.Prog {
582         p := rawgins(as, f, t)
583         if r != nil {
584                 p.Reg = r.Reg
585         }
586         return p
587 }
588
589 /*
590  * generate one instruction:
591  *      as f, t
592  */
593 func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
594         // TODO(austin): Add self-move test like in 6g (but be careful
595         // of truncation moves)
596
597         p := gc.Prog(as)
598         gc.Naddr(&p.From, f)
599         gc.Naddr(&p.To, t)
600
601         switch as {
602         case obj.ACALL:
603                 if p.To.Type == obj.TYPE_REG {
604                         // Allow front end to emit CALL REG, and rewrite into CALL (REG).
605                         p.From = obj.Addr{}
606                         p.To.Type = obj.TYPE_MEM
607                         p.To.Offset = 0
608
609                         if gc.Debug['g'] != 0 {
610                                 fmt.Printf("%v\n", p)
611                         }
612
613                         return p
614                 }
615
616         // Bad things the front end has done to us. Crash to find call stack.
617         case mips.AAND:
618                 if p.From.Type == obj.TYPE_CONST {
619                         gc.Debug['h'] = 1
620                         gc.Fatalf("bad inst: %v", p)
621                 }
622         case mips.ASGT, mips.ASGTU:
623                 if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM {
624                         gc.Debug['h'] = 1
625                         gc.Fatalf("bad inst: %v", p)
626                 }
627
628         // Special cases
629         case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU:
630                 if p.From.Type == obj.TYPE_CONST {
631                         gc.Debug['h'] = 1
632                         gc.Fatalf("bad inst: %v", p)
633                 }
634
635                 pp := gc.Prog(mips.AMOVV)
636                 pp.From.Type = obj.TYPE_REG
637                 pp.From.Reg = mips.REG_LO
638                 pp.To = p.To
639
640                 p.Reg = p.To.Reg
641                 p.To = obj.Addr{}
642
643         case mips.ASUBVU:
644                 // unary
645                 if f == nil {
646                         p.From = p.To
647                         p.Reg = mips.REGZERO
648                 }
649         }
650
651         if gc.Debug['g'] != 0 {
652                 fmt.Printf("%v\n", p)
653         }
654
655         w := int32(0)
656         switch as {
657         case mips.AMOVB,
658                 mips.AMOVBU:
659                 w = 1
660
661         case mips.AMOVH,
662                 mips.AMOVHU:
663                 w = 2
664
665         case mips.AMOVW,
666                 mips.AMOVWU:
667                 w = 4
668
669         case mips.AMOVV:
670                 if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR {
671                         break
672                 }
673                 w = 8
674         }
675
676         if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) {
677                 gc.Dump("f", f)
678                 gc.Dump("t", t)
679                 gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
680         }
681
682         return p
683 }
684
685 /*
686  * return Axxx for Oxxx on type t.
687  */
688 func optoas(op gc.Op, t *gc.Type) obj.As {
689         if t == nil {
690                 gc.Fatalf("optoas: t is nil")
691         }
692
693         // avoid constant conversions in switches below
694         const (
695                 OMINUS_ = uint32(gc.OMINUS) << 16
696                 OLSH_   = uint32(gc.OLSH) << 16
697                 ORSH_   = uint32(gc.ORSH) << 16
698                 OADD_   = uint32(gc.OADD) << 16
699                 OSUB_   = uint32(gc.OSUB) << 16
700                 OMUL_   = uint32(gc.OMUL) << 16
701                 ODIV_   = uint32(gc.ODIV) << 16
702                 OOR_    = uint32(gc.OOR) << 16
703                 OAND_   = uint32(gc.OAND) << 16
704                 OXOR_   = uint32(gc.OXOR) << 16
705                 OEQ_    = uint32(gc.OEQ) << 16
706                 ONE_    = uint32(gc.ONE) << 16
707                 OLT_    = uint32(gc.OLT) << 16
708                 OLE_    = uint32(gc.OLE) << 16
709                 OGE_    = uint32(gc.OGE) << 16
710                 OGT_    = uint32(gc.OGT) << 16
711                 OCMP_   = uint32(gc.OCMP) << 16
712                 OAS_    = uint32(gc.OAS) << 16
713                 OHMUL_  = uint32(gc.OHMUL) << 16
714         )
715
716         a := obj.AXXX
717         switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
718         default:
719                 gc.Fatalf("optoas: no entry for op=%s type=%v", op, t)
720
721         case OEQ_ | gc.TBOOL,
722                 OEQ_ | gc.TINT8,
723                 OEQ_ | gc.TUINT8,
724                 OEQ_ | gc.TINT16,
725                 OEQ_ | gc.TUINT16,
726                 OEQ_ | gc.TINT32,
727                 OEQ_ | gc.TUINT32,
728                 OEQ_ | gc.TINT64,
729                 OEQ_ | gc.TUINT64,
730                 OEQ_ | gc.TPTR32,
731                 OEQ_ | gc.TPTR64:
732                 a = mips.ABEQ
733
734         case OEQ_ | gc.TFLOAT32, // ACMPEQF
735                 OEQ_ | gc.TFLOAT64: // ACMPEQD
736                 a = mips.ABFPT
737
738         case ONE_ | gc.TBOOL,
739                 ONE_ | gc.TINT8,
740                 ONE_ | gc.TUINT8,
741                 ONE_ | gc.TINT16,
742                 ONE_ | gc.TUINT16,
743                 ONE_ | gc.TINT32,
744                 ONE_ | gc.TUINT32,
745                 ONE_ | gc.TINT64,
746                 ONE_ | gc.TUINT64,
747                 ONE_ | gc.TPTR32,
748                 ONE_ | gc.TPTR64:
749                 a = mips.ABNE
750
751         case ONE_ | gc.TFLOAT32, // ACMPEQF
752                 ONE_ | gc.TFLOAT64: // ACMPEQD
753                 a = mips.ABFPF
754
755         case OLT_ | gc.TINT8, // ASGT
756                 OLT_ | gc.TINT16,
757                 OLT_ | gc.TINT32,
758                 OLT_ | gc.TINT64,
759                 OLT_ | gc.TUINT8, // ASGTU
760                 OLT_ | gc.TUINT16,
761                 OLT_ | gc.TUINT32,
762                 OLT_ | gc.TUINT64:
763                 a = mips.ABNE
764
765         case OLT_ | gc.TFLOAT32, // ACMPGEF
766                 OLT_ | gc.TFLOAT64: // ACMPGED
767                 a = mips.ABFPT
768
769         case OLE_ | gc.TINT8, // ASGT
770                 OLE_ | gc.TINT16,
771                 OLE_ | gc.TINT32,
772                 OLE_ | gc.TINT64,
773                 OLE_ | gc.TUINT8, // ASGTU
774                 OLE_ | gc.TUINT16,
775                 OLE_ | gc.TUINT32,
776                 OLE_ | gc.TUINT64:
777                 a = mips.ABEQ
778
779         case OLE_ | gc.TFLOAT32, // ACMPGTF
780                 OLE_ | gc.TFLOAT64: // ACMPGTD
781                 a = mips.ABFPT
782
783         case OGT_ | gc.TINT8, // ASGT
784                 OGT_ | gc.TINT16,
785                 OGT_ | gc.TINT32,
786                 OGT_ | gc.TINT64,
787                 OGT_ | gc.TUINT8, // ASGTU
788                 OGT_ | gc.TUINT16,
789                 OGT_ | gc.TUINT32,
790                 OGT_ | gc.TUINT64:
791                 a = mips.ABNE
792
793         case OGT_ | gc.TFLOAT32, // ACMPGTF
794                 OGT_ | gc.TFLOAT64: // ACMPGTD
795                 a = mips.ABFPT
796
797         case OGE_ | gc.TINT8, // ASGT
798                 OGE_ | gc.TINT16,
799                 OGE_ | gc.TINT32,
800                 OGE_ | gc.TINT64,
801                 OGE_ | gc.TUINT8, // ASGTU
802                 OGE_ | gc.TUINT16,
803                 OGE_ | gc.TUINT32,
804                 OGE_ | gc.TUINT64:
805                 a = mips.ABEQ
806
807         case OGE_ | gc.TFLOAT32, // ACMPGEF
808                 OGE_ | gc.TFLOAT64: // ACMPGED
809                 a = mips.ABFPT
810
811         case OAS_ | gc.TBOOL,
812                 OAS_ | gc.TINT8:
813                 a = mips.AMOVB
814
815         case OAS_ | gc.TUINT8:
816                 a = mips.AMOVBU
817
818         case OAS_ | gc.TINT16:
819                 a = mips.AMOVH
820
821         case OAS_ | gc.TUINT16:
822                 a = mips.AMOVHU
823
824         case OAS_ | gc.TINT32:
825                 a = mips.AMOVW
826
827         case OAS_ | gc.TUINT32,
828                 OAS_ | gc.TPTR32:
829                 a = mips.AMOVWU
830
831         case OAS_ | gc.TINT64,
832                 OAS_ | gc.TUINT64,
833                 OAS_ | gc.TPTR64:
834                 a = mips.AMOVV
835
836         case OAS_ | gc.TFLOAT32:
837                 a = mips.AMOVF
838
839         case OAS_ | gc.TFLOAT64:
840                 a = mips.AMOVD
841
842         case OADD_ | gc.TINT8,
843                 OADD_ | gc.TUINT8,
844                 OADD_ | gc.TINT16,
845                 OADD_ | gc.TUINT16,
846                 OADD_ | gc.TINT32,
847                 OADD_ | gc.TUINT32,
848                 OADD_ | gc.TPTR32:
849                 a = mips.AADDU
850
851         case OADD_ | gc.TINT64,
852                 OADD_ | gc.TUINT64,
853                 OADD_ | gc.TPTR64:
854                 a = mips.AADDVU
855
856         case OADD_ | gc.TFLOAT32:
857                 a = mips.AADDF
858
859         case OADD_ | gc.TFLOAT64:
860                 a = mips.AADDD
861
862         case OSUB_ | gc.TINT8,
863                 OSUB_ | gc.TUINT8,
864                 OSUB_ | gc.TINT16,
865                 OSUB_ | gc.TUINT16,
866                 OSUB_ | gc.TINT32,
867                 OSUB_ | gc.TUINT32,
868                 OSUB_ | gc.TPTR32:
869                 a = mips.ASUBU
870
871         case OSUB_ | gc.TINT64,
872                 OSUB_ | gc.TUINT64,
873                 OSUB_ | gc.TPTR64:
874                 a = mips.ASUBVU
875
876         case OSUB_ | gc.TFLOAT32:
877                 a = mips.ASUBF
878
879         case OSUB_ | gc.TFLOAT64:
880                 a = mips.ASUBD
881
882         case OMINUS_ | gc.TINT8,
883                 OMINUS_ | gc.TUINT8,
884                 OMINUS_ | gc.TINT16,
885                 OMINUS_ | gc.TUINT16,
886                 OMINUS_ | gc.TINT32,
887                 OMINUS_ | gc.TUINT32,
888                 OMINUS_ | gc.TPTR32,
889                 OMINUS_ | gc.TINT64,
890                 OMINUS_ | gc.TUINT64,
891                 OMINUS_ | gc.TPTR64:
892                 a = mips.ASUBVU
893
894         case OAND_ | gc.TINT8,
895                 OAND_ | gc.TUINT8,
896                 OAND_ | gc.TINT16,
897                 OAND_ | gc.TUINT16,
898                 OAND_ | gc.TINT32,
899                 OAND_ | gc.TUINT32,
900                 OAND_ | gc.TPTR32,
901                 OAND_ | gc.TINT64,
902                 OAND_ | gc.TUINT64,
903                 OAND_ | gc.TPTR64:
904                 a = mips.AAND
905
906         case OOR_ | gc.TINT8,
907                 OOR_ | gc.TUINT8,
908                 OOR_ | gc.TINT16,
909                 OOR_ | gc.TUINT16,
910                 OOR_ | gc.TINT32,
911                 OOR_ | gc.TUINT32,
912                 OOR_ | gc.TPTR32,
913                 OOR_ | gc.TINT64,
914                 OOR_ | gc.TUINT64,
915                 OOR_ | gc.TPTR64:
916                 a = mips.AOR
917
918         case OXOR_ | gc.TINT8,
919                 OXOR_ | gc.TUINT8,
920                 OXOR_ | gc.TINT16,
921                 OXOR_ | gc.TUINT16,
922                 OXOR_ | gc.TINT32,
923                 OXOR_ | gc.TUINT32,
924                 OXOR_ | gc.TPTR32,
925                 OXOR_ | gc.TINT64,
926                 OXOR_ | gc.TUINT64,
927                 OXOR_ | gc.TPTR64:
928                 a = mips.AXOR
929
930                 // TODO(minux): handle rotates
931         //case CASE(OLROT, TINT8):
932         //case CASE(OLROT, TUINT8):
933         //case CASE(OLROT, TINT16):
934         //case CASE(OLROT, TUINT16):
935         //case CASE(OLROT, TINT32):
936         //case CASE(OLROT, TUINT32):
937         //case CASE(OLROT, TPTR32):
938         //case CASE(OLROT, TINT64):
939         //case CASE(OLROT, TUINT64):
940         //case CASE(OLROT, TPTR64):
941         //      a = 0//???; RLDC?
942         //      break;
943
944         case OLSH_ | gc.TINT8,
945                 OLSH_ | gc.TUINT8,
946                 OLSH_ | gc.TINT16,
947                 OLSH_ | gc.TUINT16,
948                 OLSH_ | gc.TINT32,
949                 OLSH_ | gc.TUINT32,
950                 OLSH_ | gc.TPTR32,
951                 OLSH_ | gc.TINT64,
952                 OLSH_ | gc.TUINT64,
953                 OLSH_ | gc.TPTR64:
954                 a = mips.ASLLV
955
956         case ORSH_ | gc.TUINT8,
957                 ORSH_ | gc.TUINT16,
958                 ORSH_ | gc.TUINT32,
959                 ORSH_ | gc.TPTR32,
960                 ORSH_ | gc.TUINT64,
961                 ORSH_ | gc.TPTR64:
962                 a = mips.ASRLV
963
964         case ORSH_ | gc.TINT8,
965                 ORSH_ | gc.TINT16,
966                 ORSH_ | gc.TINT32,
967                 ORSH_ | gc.TINT64:
968                 a = mips.ASRAV
969
970                 // TODO(minux): handle rotates
971         //case CASE(ORROTC, TINT8):
972         //case CASE(ORROTC, TUINT8):
973         //case CASE(ORROTC, TINT16):
974         //case CASE(ORROTC, TUINT16):
975         //case CASE(ORROTC, TINT32):
976         //case CASE(ORROTC, TUINT32):
977         //case CASE(ORROTC, TINT64):
978         //case CASE(ORROTC, TUINT64):
979         //      a = 0//??? RLDC??
980         //      break;
981
982         case OHMUL_ | gc.TINT64:
983                 a = mips.AMULV
984
985         case OHMUL_ | gc.TUINT64,
986                 OHMUL_ | gc.TPTR64:
987                 a = mips.AMULVU
988
989         case OMUL_ | gc.TINT8,
990                 OMUL_ | gc.TINT16,
991                 OMUL_ | gc.TINT32,
992                 OMUL_ | gc.TINT64:
993                 a = mips.AMULV
994
995         case OMUL_ | gc.TUINT8,
996                 OMUL_ | gc.TUINT16,
997                 OMUL_ | gc.TUINT32,
998                 OMUL_ | gc.TPTR32,
999                 OMUL_ | gc.TUINT64,
1000                 OMUL_ | gc.TPTR64:
1001                 a = mips.AMULVU
1002
1003         case OMUL_ | gc.TFLOAT32:
1004                 a = mips.AMULF
1005
1006         case OMUL_ | gc.TFLOAT64:
1007                 a = mips.AMULD
1008
1009         case ODIV_ | gc.TINT8,
1010                 ODIV_ | gc.TINT16,
1011                 ODIV_ | gc.TINT32,
1012                 ODIV_ | gc.TINT64:
1013                 a = mips.ADIVV
1014
1015         case ODIV_ | gc.TUINT8,
1016                 ODIV_ | gc.TUINT16,
1017                 ODIV_ | gc.TUINT32,
1018                 ODIV_ | gc.TPTR32,
1019                 ODIV_ | gc.TUINT64,
1020                 ODIV_ | gc.TPTR64:
1021                 a = mips.ADIVVU
1022
1023         case ODIV_ | gc.TFLOAT32:
1024                 a = mips.ADIVF
1025
1026         case ODIV_ | gc.TFLOAT64:
1027                 a = mips.ADIVD
1028         }
1029
1030         return a
1031 }
1032
1033 const (
1034         ODynam   = 1 << 0
1035         OAddable = 1 << 1
1036 )
1037
1038 func xgen(n *gc.Node, a *gc.Node, o int) bool {
1039         // TODO(minux)
1040
1041         return -1 != 0 /*TypeKind(100016)*/
1042 }
1043
1044 func sudoclean() {
1045         return
1046 }
1047
1048 /*
1049  * generate code to compute address of n,
1050  * a reference to a (perhaps nested) field inside
1051  * an array or struct.
1052  * return 0 on failure, 1 on success.
1053  * on success, leaves usable address in a.
1054  *
1055  * caller is responsible for calling sudoclean
1056  * after successful sudoaddable,
1057  * to release the register used for a.
1058  */
1059 func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
1060         // TODO(minux)
1061
1062         *a = obj.Addr{}
1063         return false
1064 }