1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ir"
10 "cmd/compile/internal/logopt"
11 "cmd/compile/internal/reflectdata"
12 "cmd/compile/internal/rttype"
13 "cmd/compile/internal/typecheck"
14 "cmd/compile/internal/types"
15 "cmd/internal/obj"
16 "cmd/internal/obj/s390x"
17 "cmd/internal/objabi"
18 "cmd/internal/src"
19 "encoding/binary"
20 "fmt"
21 "internal/buildcfg"
22 "io"
23 "math"
24 "math/bits"
25 "os"
26 "path/filepath"
27 "strings"
28 )
29
30 type deadValueChoice bool
31
32 const (
33 leaveDeadValues deadValueChoice = false
34 removeDeadValues = true
35
36 repZeroThreshold = 1408
37 repMoveThreshold = 1408
38 )
39
40
41 func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter, deadcode deadValueChoice) {
42
43 pendingLines := f.cachedLineStarts
44 pendingLines.clear()
45 debug := f.pass.debug
46 if debug > 1 {
47 fmt.Printf("%s: rewriting for %s\n", f.pass.name, f.Name)
48 }
49
50
51
52
53 itersLimit := f.NumBlocks()
54 if itersLimit < 20 {
55 itersLimit = 20
56 }
57 var iters int
58 var states map[string]bool
59 for {
60 if debug > 1 {
61 fmt.Printf("%s: iter %d\n", f.pass.name, iters)
62 }
63 change := false
64 deadChange := false
65 for _, b := range f.Blocks {
66 var b0 *Block
67 if debug > 1 {
68 fmt.Printf("%s: start block\n", f.pass.name)
69 b0 = new(Block)
70 *b0 = *b
71 b0.Succs = append([]Edge{}, b.Succs...)
72 }
73 for i, c := range b.ControlValues() {
74 for c.Op == OpCopy {
75 c = c.Args[0]
76 b.ReplaceControl(i, c)
77 }
78 }
79 if rb(b) {
80 change = true
81 if debug > 1 {
82 fmt.Printf("rewriting %s -> %s\n", b0.LongString(), b.LongString())
83 }
84 }
85 for j, v := range b.Values {
86 if debug > 1 {
87 fmt.Printf("%s: consider %v\n", f.pass.name, v.LongString())
88 }
89 var v0 *Value
90 if debug > 1 {
91 v0 = new(Value)
92 *v0 = *v
93 v0.Args = append([]*Value{}, v.Args...)
94 }
95 if v.Uses == 0 && v.removeable() {
96 if v.Op != OpInvalid && deadcode == removeDeadValues {
97
98
99
100
101 v.reset(OpInvalid)
102 deadChange = true
103 }
104
105 continue
106 }
107
108 vchange := phielimValue(v)
109 if vchange && debug > 1 {
110 fmt.Printf("rewriting %s -> %s\n", v0.LongString(), v.LongString())
111 }
112
113
114
115
116
117
118
119
120 for i, a := range v.Args {
121 if a.Op != OpCopy {
122 continue
123 }
124 aa := copySource(a)
125 v.SetArg(i, aa)
126
127
128
129
130
131 if a.Pos.IsStmt() == src.PosIsStmt {
132 if aa.Block == a.Block && aa.Pos.Line() == a.Pos.Line() && aa.Pos.IsStmt() != src.PosNotStmt {
133 aa.Pos = aa.Pos.WithIsStmt()
134 } else if v.Block == a.Block && v.Pos.Line() == a.Pos.Line() && v.Pos.IsStmt() != src.PosNotStmt {
135 v.Pos = v.Pos.WithIsStmt()
136 } else {
137
138
139
140
141 pendingLines.set(a.Pos, int32(a.Block.ID))
142 }
143 a.Pos = a.Pos.WithNotStmt()
144 }
145 vchange = true
146 for a.Uses == 0 {
147 b := a.Args[0]
148 a.reset(OpInvalid)
149 a = b
150 }
151 }
152 if vchange && debug > 1 {
153 fmt.Printf("rewriting %s -> %s\n", v0.LongString(), v.LongString())
154 }
155
156
157 if rv(v) {
158 vchange = true
159
160 if v.Pos.IsStmt() == src.PosIsStmt {
161 if k := nextGoodStatementIndex(v, j, b); k != j {
162 v.Pos = v.Pos.WithNotStmt()
163 b.Values[k].Pos = b.Values[k].Pos.WithIsStmt()
164 }
165 }
166 }
167
168 change = change || vchange
169 if vchange && debug > 1 {
170 fmt.Printf("rewriting %s -> %s\n", v0.LongString(), v.LongString())
171 }
172 }
173 }
174 if !change && !deadChange {
175 break
176 }
177 iters++
178 if (iters > itersLimit || debug >= 2) && change {
179
180
181
182
183
184 if states == nil {
185 states = make(map[string]bool)
186 }
187 h := f.rewriteHash()
188 if _, ok := states[h]; ok {
189
190
191
192
193 if debug < 2 {
194 debug = 2
195 states = make(map[string]bool)
196 } else {
197 f.Fatalf("rewrite cycle detected")
198 }
199 }
200 states[h] = true
201 }
202 }
203
204 for _, b := range f.Blocks {
205 j := 0
206 for i, v := range b.Values {
207 vl := v.Pos
208 if v.Op == OpInvalid {
209 if v.Pos.IsStmt() == src.PosIsStmt {
210 pendingLines.set(vl, int32(b.ID))
211 }
212 f.freeValue(v)
213 continue
214 }
215 if v.Pos.IsStmt() != src.PosNotStmt && !notStmtBoundary(v.Op) {
216 if pl, ok := pendingLines.get(vl); ok && pl == int32(b.ID) {
217 pendingLines.remove(vl)
218 v.Pos = v.Pos.WithIsStmt()
219 }
220 }
221 if i != j {
222 b.Values[j] = v
223 }
224 j++
225 }
226 if pl, ok := pendingLines.get(b.Pos); ok && pl == int32(b.ID) {
227 b.Pos = b.Pos.WithIsStmt()
228 pendingLines.remove(b.Pos)
229 }
230 b.truncateValues(j)
231 }
232 }
233
234
235
236 func is64BitFloat(t *types.Type) bool {
237 return t.Size() == 8 && t.IsFloat()
238 }
239
240 func is32BitFloat(t *types.Type) bool {
241 return t.Size() == 4 && t.IsFloat()
242 }
243
244 func is64BitInt(t *types.Type) bool {
245 return t.Size() == 8 && t.IsInteger()
246 }
247
248 func is32BitInt(t *types.Type) bool {
249 return t.Size() == 4 && t.IsInteger()
250 }
251
252 func is16BitInt(t *types.Type) bool {
253 return t.Size() == 2 && t.IsInteger()
254 }
255
256 func is8BitInt(t *types.Type) bool {
257 return t.Size() == 1 && t.IsInteger()
258 }
259
260 func isPtr(t *types.Type) bool {
261 return t.IsPtrShaped()
262 }
263
264 func copyCompatibleType(t1, t2 *types.Type) bool {
265 if t1.Size() != t2.Size() {
266 return false
267 }
268 if t1.IsInteger() {
269 return t2.IsInteger()
270 }
271 if isPtr(t1) {
272 return isPtr(t2)
273 }
274 return t1.Compare(t2) == types.CMPeq
275 }
276
277
278
279 func mergeSym(x, y Sym) Sym {
280 if x == nil {
281 return y
282 }
283 if y == nil {
284 return x
285 }
286 panic(fmt.Sprintf("mergeSym with two non-nil syms %v %v", x, y))
287 }
288
289 func canMergeSym(x, y Sym) bool {
290 return x == nil || y == nil
291 }
292
293
294
295
296
297 func canMergeLoadClobber(target, load, x *Value) bool {
298
299
300
301
302
303
304 switch {
305 case x.Uses == 2 && x.Op == OpPhi && len(x.Args) == 2 && (x.Args[0] == target || x.Args[1] == target) && target.Uses == 1:
306
307
308
309
310
311
312
313
314
315 case x.Uses > 1:
316 return false
317 }
318 loopnest := x.Block.Func.loopnest()
319 if loopnest.depth(target.Block.ID) > loopnest.depth(x.Block.ID) {
320 return false
321 }
322 return canMergeLoad(target, load)
323 }
324
325
326
327 func canMergeLoad(target, load *Value) bool {
328 if target.Block.ID != load.Block.ID {
329
330 return false
331 }
332
333
334
335 if load.Uses != 1 {
336 return false
337 }
338
339 mem := load.MemoryArg()
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356 var args []*Value
357 for _, a := range target.Args {
358 if a != load && a.Block.ID == target.Block.ID {
359 args = append(args, a)
360 }
361 }
362
363 f := target.Block.Func
364 visited := f.newSparseSet(f.NumValues())
365 defer f.retSparseSet(visited)
366
367
368
369 var memPreds map[*Value]bool
370 for len(args) > 0 {
371 const limit = 2048
372 if visited.size() >= limit {
373
374 return false
375 }
376 v := args[len(args)-1]
377 args = args[:len(args)-1]
378 if visited.contains(v.ID) {
379 continue
380 }
381 visited.add(v.ID)
382 if target.Block.ID != v.Block.ID {
383
384
385 continue
386 }
387 if v.Op == OpPhi {
388
389
390
391 continue
392 }
393 if v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
394
395
396 return false
397 }
398 if v.Op.SymEffect()&SymAddr != 0 {
399
400
401
402
403
404
405
406
407
408
409
410 return false
411 }
412 if v.Type.IsMemory() {
413 if memPreds == nil {
414
415
416
417 memPreds = make(map[*Value]bool)
418 m := mem
419 const limit = 50
420 for i := 0; i < limit; i++ {
421 if m.Op == OpPhi {
422
423
424 break
425 }
426 if m.Block.ID != target.Block.ID {
427 break
428 }
429 if !m.Type.IsMemory() {
430 break
431 }
432 memPreds[m] = true
433 if len(m.Args) == 0 {
434 break
435 }
436 m = m.MemoryArg()
437 }
438 }
439
440
441
442
443
444
445
446
447
448 if memPreds[v] {
449 continue
450 }
451 return false
452 }
453 if len(v.Args) > 0 && v.Args[len(v.Args)-1] == mem {
454
455
456 continue
457 }
458 for _, a := range v.Args {
459 if target.Block.ID == a.Block.ID {
460 args = append(args, a)
461 }
462 }
463 }
464
465 return true
466 }
467
468
469 func isSameCall(aux Aux, name string) bool {
470 fn := aux.(*AuxCall).Fn
471 return fn != nil && fn.String() == name
472 }
473
474 func isMalloc(aux Aux) bool {
475 return isNewObject(aux) || isSpecializedMalloc(aux)
476 }
477
478 func isNewObject(aux Aux) bool {
479 fn := aux.(*AuxCall).Fn
480 return fn != nil && fn.String() == "runtime.newobject"
481 }
482
483 func isSpecializedMalloc(aux Aux) bool {
484 fn := aux.(*AuxCall).Fn
485 if fn == nil {
486 return false
487 }
488 name := fn.String()
489 return strings.HasPrefix(name, "runtime.mallocgcSmallNoScanSC") ||
490 strings.HasPrefix(name, "runtime.mallocgcSmallScanNoHeaderSC") ||
491 strings.HasPrefix(name, "runtime.mallocgcTinySC")
492 }
493
494
495 func canLoadUnaligned(c *Config) bool {
496 return c.ctxt.Arch.Alignment == 1
497 }
498
499
500 func nlz64(x int64) int { return bits.LeadingZeros64(uint64(x)) }
501 func nlz32(x int32) int { return bits.LeadingZeros32(uint32(x)) }
502 func nlz16(x int16) int { return bits.LeadingZeros16(uint16(x)) }
503 func nlz8(x int8) int { return bits.LeadingZeros8(uint8(x)) }
504
505
506 func ntz64(x int64) int { return bits.TrailingZeros64(uint64(x)) }
507 func ntz32(x int32) int { return bits.TrailingZeros32(uint32(x)) }
508 func ntz16(x int16) int { return bits.TrailingZeros16(uint16(x)) }
509 func ntz8(x int8) int { return bits.TrailingZeros8(uint8(x)) }
510
511
512 func oneBit[T int8 | int16 | int32 | int64](x T) bool {
513 return x&(x-1) == 0 && x != 0
514 }
515
516
517 func nto(x int64) int64 {
518 return int64(ntz64(^x))
519 }
520
521
522
523 func log8(n int8) int64 { return log8u(uint8(n)) }
524 func log16(n int16) int64 { return log16u(uint16(n)) }
525 func log32(n int32) int64 { return log32u(uint32(n)) }
526 func log64(n int64) int64 { return log64u(uint64(n)) }
527
528
529
530 func log8u(n uint8) int64 { return int64(bits.Len8(n)) - 1 }
531 func log16u(n uint16) int64 { return int64(bits.Len16(n)) - 1 }
532 func log32u(n uint32) int64 { return int64(bits.Len32(n)) - 1 }
533 func log64u(n uint64) int64 { return int64(bits.Len64(n)) - 1 }
534
535
536 func isPowerOfTwo[T int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64](n T) bool {
537 return n > 0 && n&(n-1) == 0
538 }
539
540
541 func is32Bit(n int64) bool {
542 return n == int64(int32(n))
543 }
544
545
546 func is16Bit(n int64) bool {
547 return n == int64(int16(n))
548 }
549
550
551 func is8Bit(n int64) bool {
552 return n == int64(int8(n))
553 }
554
555
556 func isU8Bit(n int64) bool {
557 return n == int64(uint8(n))
558 }
559
560
561 func is12Bit(n int64) bool {
562 return -(1<<11) <= n && n < (1<<11)
563 }
564
565
566 func isU12Bit(n int64) bool {
567 return 0 <= n && n < (1<<12)
568 }
569
570
571 func isU16Bit(n int64) bool {
572 return n == int64(uint16(n))
573 }
574
575
576 func isU32Bit(n int64) bool {
577 return n == int64(uint32(n))
578 }
579
580
581 func is20Bit(n int64) bool {
582 return -(1<<19) <= n && n < (1<<19)
583 }
584
585
586 func b2i(b bool) int64 {
587 if b {
588 return 1
589 }
590 return 0
591 }
592
593
594 func b2i32(b bool) int32 {
595 if b {
596 return 1
597 }
598 return 0
599 }
600
601 func canMulStrengthReduce(config *Config, x int64) bool {
602 _, ok := config.mulRecipes[x]
603 return ok
604 }
605 func canMulStrengthReduce32(config *Config, x int32) bool {
606 _, ok := config.mulRecipes[int64(x)]
607 return ok
608 }
609
610
611
612
613 func mulStrengthReduce(m *Value, v *Value, x int64) *Value {
614 return v.Block.Func.Config.mulRecipes[x].build(m, v)
615 }
616
617
618
619
620
621 func mulStrengthReduce32(m *Value, v *Value, x int32) *Value {
622 return v.Block.Func.Config.mulRecipes[int64(x)].build(m, v)
623 }
624
625
626
627 func shiftIsBounded(v *Value) bool {
628 return v.AuxInt != 0
629 }
630
631
632
633 func canonLessThan(x, y *Value) bool {
634 if x.Op != y.Op {
635 return x.Op < y.Op
636 }
637 if !x.Pos.SameFileAndLine(y.Pos) {
638 return x.Pos.Before(y.Pos)
639 }
640 return x.ID < y.ID
641 }
642
643
644
645 func truncate64Fto32F(f float64) float32 {
646 if !isExactFloat32(f) {
647 panic("truncate64Fto32F: truncation is not exact")
648 }
649 if !math.IsNaN(f) {
650 return float32(f)
651 }
652
653
654 b := math.Float64bits(f)
655 m := b & ((1 << 52) - 1)
656
657 r := uint32(((b >> 32) & (1 << 31)) | 0x7f800000 | (m >> (52 - 23)))
658 return math.Float32frombits(r)
659 }
660
661
662 func DivisionNeedsFixUp(v *Value) bool {
663 return v.AuxInt == 0
664 }
665
666
667 func auxTo32F(i int64) float32 {
668 return truncate64Fto32F(math.Float64frombits(uint64(i)))
669 }
670
671 func auxIntToBool(i int64) bool {
672 if i == 0 {
673 return false
674 }
675 return true
676 }
677 func auxIntToInt8(i int64) int8 {
678 return int8(i)
679 }
680 func auxIntToInt16(i int64) int16 {
681 return int16(i)
682 }
683 func auxIntToInt32(i int64) int32 {
684 return int32(i)
685 }
686 func auxIntToInt64(i int64) int64 {
687 return i
688 }
689 func auxIntToUint8(i int64) uint8 {
690 return uint8(i)
691 }
692 func auxIntToUint64(i int64) uint64 {
693 return uint64(i)
694 }
695 func auxIntToFloat32(i int64) float32 {
696 return float32(math.Float64frombits(uint64(i)))
697 }
698 func auxIntToFloat64(i int64) float64 {
699 return math.Float64frombits(uint64(i))
700 }
701 func auxIntToValAndOff(i int64) ValAndOff {
702 return ValAndOff(i)
703 }
704 func auxIntToArm64BitField(i int64) arm64BitField {
705 return arm64BitField(i)
706 }
707 func auxIntToArm64ConditionalParams(i int64) arm64ConditionalParams {
708 var params arm64ConditionalParams
709 params.cond = Op(i & 0xffff)
710 i >>= 16
711 params.nzcv = uint8(i & 0x0f)
712 i >>= 4
713 params.constValue = uint8(i & 0x1f)
714 i >>= 5
715 params.ind = i == 1
716 return params
717 }
718 func auxIntToFlagConstant(x int64) flagConstant {
719 return flagConstant(x)
720 }
721
722 func auxIntToOp(cc int64) Op {
723 return Op(cc)
724 }
725
726 func boolToAuxInt(b bool) int64 {
727 if b {
728 return 1
729 }
730 return 0
731 }
732 func int8ToAuxInt(i int8) int64 {
733 return int64(i)
734 }
735 func int16ToAuxInt(i int16) int64 {
736 return int64(i)
737 }
738 func int32ToAuxInt(i int32) int64 {
739 return int64(i)
740 }
741 func int64ToAuxInt(i int64) int64 {
742 return i
743 }
744 func uint8ToAuxInt(i uint8) int64 {
745 return int64(int8(i))
746 }
747 func uint64ToAuxInt(i uint64) int64 {
748 return int64(i)
749 }
750 func float32ToAuxInt(f float32) int64 {
751 return int64(math.Float64bits(float64(f)))
752 }
753 func float64ToAuxInt(f float64) int64 {
754 return int64(math.Float64bits(f))
755 }
756 func valAndOffToAuxInt(v ValAndOff) int64 {
757 return int64(v)
758 }
759 func arm64BitFieldToAuxInt(v arm64BitField) int64 {
760 return int64(v)
761 }
762 func arm64ConditionalParamsToAuxInt(v arm64ConditionalParams) int64 {
763 if v.cond&^0xffff != 0 {
764 panic("condition value exceeds 16 bits")
765 }
766
767 var i int64
768 if v.ind {
769 i = 1 << 25
770 }
771 i |= int64(v.constValue) << 20
772 i |= int64(v.nzcv) << 16
773 i |= int64(v.cond)
774 return i
775 }
776
777 func flagConstantToAuxInt(x flagConstant) int64 {
778 return int64(x)
779 }
780
781 func opToAuxInt(o Op) int64 {
782 return int64(o)
783 }
784
785
786 type Aux interface {
787 CanBeAnSSAAux()
788 }
789
790
791 type auxMark bool
792
793 func (auxMark) CanBeAnSSAAux() {}
794
795 var AuxMark auxMark
796
797
798 type stringAux string
799
800 func (stringAux) CanBeAnSSAAux() {}
801
802 func auxToString(i Aux) string {
803 return string(i.(stringAux))
804 }
805 func auxToSym(i Aux) Sym {
806
807 s, _ := i.(Sym)
808 return s
809 }
810 func auxToType(i Aux) *types.Type {
811 return i.(*types.Type)
812 }
813 func auxToCall(i Aux) *AuxCall {
814 return i.(*AuxCall)
815 }
816 func auxToS390xCCMask(i Aux) s390x.CCMask {
817 return i.(s390x.CCMask)
818 }
819 func auxToS390xRotateParams(i Aux) s390x.RotateParams {
820 return i.(s390x.RotateParams)
821 }
822
823 func StringToAux(s string) Aux {
824 return stringAux(s)
825 }
826 func symToAux(s Sym) Aux {
827 return s
828 }
829 func callToAux(s *AuxCall) Aux {
830 return s
831 }
832 func typeToAux(t *types.Type) Aux {
833 return t
834 }
835 func s390xCCMaskToAux(c s390x.CCMask) Aux {
836 return c
837 }
838 func s390xRotateParamsToAux(r s390x.RotateParams) Aux {
839 return r
840 }
841
842
843 func uaddOvf(a, b int64) bool {
844 return uint64(a)+uint64(b) < uint64(a)
845 }
846
847 func devirtLECall(v *Value, sym *obj.LSym) *Value {
848 v.Op = OpStaticLECall
849 auxcall := v.Aux.(*AuxCall)
850 auxcall.Fn = sym
851
852 v.Args[0].Uses--
853 copy(v.Args[0:], v.Args[1:])
854 v.Args[len(v.Args)-1] = nil
855 v.Args = v.Args[:len(v.Args)-1]
856 if f := v.Block.Func; f.pass.debug > 0 {
857 f.Warnl(v.Pos, "de-virtualizing call")
858 }
859 return v
860 }
861
862
863 func isSamePtr(p1, p2 *Value) bool {
864 if p1 == p2 {
865 return true
866 }
867 if p1.Op != p2.Op {
868 for p1.Op == OpOffPtr && p1.AuxInt == 0 {
869 p1 = p1.Args[0]
870 }
871 for p2.Op == OpOffPtr && p2.AuxInt == 0 {
872 p2 = p2.Args[0]
873 }
874 if p1 == p2 {
875 return true
876 }
877 if p1.Op != p2.Op {
878 return false
879 }
880 }
881 switch p1.Op {
882 case OpOffPtr:
883 return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0])
884 case OpAddr, OpLocalAddr:
885 return p1.Aux == p2.Aux
886 case OpAddPtr:
887 return p1.Args[1] == p2.Args[1] && isSamePtr(p1.Args[0], p2.Args[0])
888 }
889 return false
890 }
891
892 func isStackPtr(v *Value) bool {
893 for v.Op == OpOffPtr || v.Op == OpAddPtr {
894 v = v.Args[0]
895 }
896 return v.Op == OpSP || v.Op == OpLocalAddr
897 }
898
899
900
901
902 func disjoint(p1 *Value, t1 *types.Type, p2 *Value, t2 *types.Type) bool {
903 return disjoint1(p1, t1.Size(), p2, t2.Size())
904 }
905
906
907
908
909 func disjoint1(p1 *Value, n1 int64, p2 *Value, n2 int64) bool {
910 if n1 == 0 || n2 == 0 {
911 return true
912 }
913 if p1 == p2 {
914 return false
915 }
916 baseAndOffset := func(ptr *Value) (base *Value, offset int64) {
917 base, offset = ptr, 0
918 for base.Op == OpOffPtr {
919 offset += base.AuxInt
920 base = base.Args[0]
921 }
922 if opcodeTable[base.Op].nilCheck {
923 base = base.Args[0]
924 }
925 return base, offset
926 }
927
928
929 if disjointTypes(p1.Type, p2.Type) {
930 return true
931 }
932
933 p1, off1 := baseAndOffset(p1)
934 p2, off2 := baseAndOffset(p2)
935 if isSamePtr(p1, p2) {
936 return !overlap(off1, n1, off2, n2)
937 }
938
939
940
941
942 switch p1.Op {
943 case OpAddr, OpLocalAddr:
944 if p2.Op == OpAddr || p2.Op == OpLocalAddr || p2.Op == OpSP {
945 return true
946 }
947 return (p2.Op == OpArg || p2.Op == OpArgIntReg) && p1.Args[0].Op == OpSP
948 case OpArg, OpArgIntReg:
949 if p2.Op == OpSP || p2.Op == OpLocalAddr {
950 return true
951 }
952 case OpSP:
953 return p2.Op == OpAddr || p2.Op == OpLocalAddr || p2.Op == OpArg || p2.Op == OpArgIntReg || p2.Op == OpSP
954 }
955 return false
956 }
957
958
959
960
961 func disjointTypes(t1 *types.Type, t2 *types.Type) bool {
962
963 if t1.IsUnsafePtr() || t2.IsUnsafePtr() {
964 return false
965 }
966
967 if !t1.IsPtr() || !t2.IsPtr() {
968
969 return false
970 }
971
972 t1 = t1.Elem()
973 t2 = t2.Elem()
974
975
976
977 if t1.NotInHeap() || t2.NotInHeap() {
978 return false
979 }
980
981 isPtrShaped := func(t *types.Type) bool { return int(t.Size()) == types.PtrSize && t.HasPointers() }
982
983
984 if (isPtrShaped(t1) && !t2.HasPointers()) ||
985 (isPtrShaped(t2) && !t1.HasPointers()) {
986 return true
987 }
988
989 return false
990 }
991
992
993 func moveSize(align int64, c *Config) int64 {
994 switch {
995 case align%8 == 0 && c.PtrSize == 8:
996 return 8
997 case align%4 == 0:
998 return 4
999 case align%2 == 0:
1000 return 2
1001 }
1002 return 1
1003 }
1004
1005
1006
1007
1008 func mergePoint(b *Block, a ...*Value) *Block {
1009
1010
1011
1012 d := 100
1013
1014 for d > 0 {
1015 for _, x := range a {
1016 if b == x.Block {
1017 goto found
1018 }
1019 }
1020 if len(b.Preds) > 1 {
1021
1022 return nil
1023 }
1024 b = b.Preds[0].b
1025 d--
1026 }
1027 return nil
1028 found:
1029
1030
1031 r := b
1032
1033
1034 na := 0
1035 for d > 0 {
1036 for _, x := range a {
1037 if b == x.Block {
1038 na++
1039 }
1040 }
1041 if na == len(a) {
1042
1043 return r
1044 }
1045 if len(b.Preds) > 1 {
1046 return nil
1047 }
1048 b = b.Preds[0].b
1049 d--
1050
1051 }
1052 return nil
1053 }
1054
1055
1056
1057
1058
1059
1060 func clobber(vv ...*Value) bool {
1061 for _, v := range vv {
1062 v.reset(OpInvalid)
1063
1064 }
1065 return true
1066 }
1067
1068
1069
1070 func resetCopy(v *Value, arg *Value) bool {
1071 v.reset(OpCopy)
1072 v.AddArg(arg)
1073 return true
1074 }
1075
1076
1077
1078
1079 func clobberIfDead(v *Value) bool {
1080 if v.Uses == 1 {
1081 v.reset(OpInvalid)
1082 }
1083
1084 return true
1085 }
1086
1087
1088
1089
1090
1091
1092
1093 func noteRule(s string) bool {
1094 fmt.Println(s)
1095 return true
1096 }
1097
1098
1099
1100
1101
1102
1103 func countRule(v *Value, key string) bool {
1104 f := v.Block.Func
1105 if f.ruleMatches == nil {
1106 f.ruleMatches = make(map[string]int)
1107 }
1108 f.ruleMatches[key]++
1109 return true
1110 }
1111
1112
1113
1114 func warnRule(cond bool, v *Value, s string) bool {
1115 if pos := v.Pos; pos.Line() > 1 && cond {
1116 v.Block.Func.Warnl(pos, s)
1117 }
1118 return true
1119 }
1120
1121
1122 func flagArg(v *Value) *Value {
1123 if len(v.Args) != 1 || !v.Args[0].Type.IsFlags() {
1124 return nil
1125 }
1126 return v.Args[0]
1127 }
1128
1129
1130
1131
1132
1133
1134
1135 func amd64CapAVXShift(auxInt int64) uint8 {
1136 u := auxIntToUint64(auxInt)
1137 if u > 255 {
1138 return 255
1139 }
1140 return uint8(u)
1141 }
1142
1143
1144
1145
1146
1147
1148 func arm64Negate(op Op) Op {
1149 switch op {
1150 case OpARM64LessThan:
1151 return OpARM64GreaterEqual
1152 case OpARM64LessThanU:
1153 return OpARM64GreaterEqualU
1154 case OpARM64GreaterThan:
1155 return OpARM64LessEqual
1156 case OpARM64GreaterThanU:
1157 return OpARM64LessEqualU
1158 case OpARM64LessEqual:
1159 return OpARM64GreaterThan
1160 case OpARM64LessEqualU:
1161 return OpARM64GreaterThanU
1162 case OpARM64GreaterEqual:
1163 return OpARM64LessThan
1164 case OpARM64GreaterEqualU:
1165 return OpARM64LessThanU
1166 case OpARM64Equal:
1167 return OpARM64NotEqual
1168 case OpARM64NotEqual:
1169 return OpARM64Equal
1170 case OpARM64LessThanF:
1171 return OpARM64NotLessThanF
1172 case OpARM64NotLessThanF:
1173 return OpARM64LessThanF
1174 case OpARM64LessEqualF:
1175 return OpARM64NotLessEqualF
1176 case OpARM64NotLessEqualF:
1177 return OpARM64LessEqualF
1178 case OpARM64GreaterThanF:
1179 return OpARM64NotGreaterThanF
1180 case OpARM64NotGreaterThanF:
1181 return OpARM64GreaterThanF
1182 case OpARM64GreaterEqualF:
1183 return OpARM64NotGreaterEqualF
1184 case OpARM64NotGreaterEqualF:
1185 return OpARM64GreaterEqualF
1186 default:
1187 panic("unreachable")
1188 }
1189 }
1190
1191
1192
1193
1194
1195
1196 func arm64Invert(op Op) Op {
1197 switch op {
1198 case OpARM64LessThan:
1199 return OpARM64GreaterThan
1200 case OpARM64LessThanU:
1201 return OpARM64GreaterThanU
1202 case OpARM64GreaterThan:
1203 return OpARM64LessThan
1204 case OpARM64GreaterThanU:
1205 return OpARM64LessThanU
1206 case OpARM64LessEqual:
1207 return OpARM64GreaterEqual
1208 case OpARM64LessEqualU:
1209 return OpARM64GreaterEqualU
1210 case OpARM64GreaterEqual:
1211 return OpARM64LessEqual
1212 case OpARM64GreaterEqualU:
1213 return OpARM64LessEqualU
1214 case OpARM64Equal, OpARM64NotEqual:
1215 return op
1216 case OpARM64LessThanF:
1217 return OpARM64GreaterThanF
1218 case OpARM64GreaterThanF:
1219 return OpARM64LessThanF
1220 case OpARM64LessEqualF:
1221 return OpARM64GreaterEqualF
1222 case OpARM64GreaterEqualF:
1223 return OpARM64LessEqualF
1224 case OpARM64NotLessThanF:
1225 return OpARM64NotGreaterThanF
1226 case OpARM64NotGreaterThanF:
1227 return OpARM64NotLessThanF
1228 case OpARM64NotLessEqualF:
1229 return OpARM64NotGreaterEqualF
1230 case OpARM64NotGreaterEqualF:
1231 return OpARM64NotLessEqualF
1232 default:
1233 panic("unreachable")
1234 }
1235 }
1236
1237
1238
1239
1240 func ccARM64Eval(op Op, flags *Value) int {
1241 fop := flags.Op
1242 if fop == OpARM64InvertFlags {
1243 return -ccARM64Eval(op, flags.Args[0])
1244 }
1245 if fop != OpARM64FlagConstant {
1246 return 0
1247 }
1248 fc := flagConstant(flags.AuxInt)
1249 b2i := func(b bool) int {
1250 if b {
1251 return 1
1252 }
1253 return -1
1254 }
1255 switch op {
1256 case OpARM64Equal:
1257 return b2i(fc.eq())
1258 case OpARM64NotEqual:
1259 return b2i(fc.ne())
1260 case OpARM64LessThan:
1261 return b2i(fc.lt())
1262 case OpARM64LessThanU:
1263 return b2i(fc.ult())
1264 case OpARM64GreaterThan:
1265 return b2i(fc.gt())
1266 case OpARM64GreaterThanU:
1267 return b2i(fc.ugt())
1268 case OpARM64LessEqual:
1269 return b2i(fc.le())
1270 case OpARM64LessEqualU:
1271 return b2i(fc.ule())
1272 case OpARM64GreaterEqual:
1273 return b2i(fc.ge())
1274 case OpARM64GreaterEqualU:
1275 return b2i(fc.uge())
1276 }
1277 return 0
1278 }
1279
1280
1281
1282 func logRule(s string) {
1283 if ruleFile == nil {
1284
1285
1286
1287
1288
1289
1290 w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"),
1291 os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
1292 if err != nil {
1293 panic(err)
1294 }
1295 ruleFile = w
1296 }
1297
1298 fmt.Fprintln(ruleFile, s)
1299 }
1300
1301 var ruleFile io.Writer
1302
1303 func isConstZero(v *Value) bool {
1304 switch v.Op {
1305 case OpConstNil:
1306 return true
1307 case OpConst64, OpConst32, OpConst16, OpConst8, OpConstBool, OpConst32F, OpConst64F:
1308 return v.AuxInt == 0
1309 case OpStringMake, OpIMake, OpComplexMake:
1310 return isConstZero(v.Args[0]) && isConstZero(v.Args[1])
1311 case OpSliceMake:
1312 return isConstZero(v.Args[0]) && isConstZero(v.Args[1]) && isConstZero(v.Args[2])
1313 case OpStringPtr, OpStringLen, OpSlicePtr, OpSliceLen, OpSliceCap, OpITab, OpIData, OpComplexReal, OpComplexImag:
1314 return isConstZero(v.Args[0])
1315 }
1316 return false
1317 }
1318
1319
1320 func reciprocalExact64(c float64) bool {
1321 b := math.Float64bits(c)
1322 man := b & (1<<52 - 1)
1323 if man != 0 {
1324 return false
1325 }
1326 exp := b >> 52 & (1<<11 - 1)
1327
1328
1329 switch exp {
1330 case 0:
1331 return false
1332 case 0x7ff:
1333 return false
1334 case 0x7fe:
1335 return false
1336 default:
1337 return true
1338 }
1339 }
1340
1341
1342 func reciprocalExact32(c float32) bool {
1343 b := math.Float32bits(c)
1344 man := b & (1<<23 - 1)
1345 if man != 0 {
1346 return false
1347 }
1348 exp := b >> 23 & (1<<8 - 1)
1349
1350
1351 switch exp {
1352 case 0:
1353 return false
1354 case 0xff:
1355 return false
1356 case 0xfe:
1357 return false
1358 default:
1359 return true
1360 }
1361 }
1362
1363
1364 func isARMImmRot(v uint32) bool {
1365 for i := 0; i < 16; i++ {
1366 if v&^0xff == 0 {
1367 return true
1368 }
1369 v = v<<2 | v>>30
1370 }
1371
1372 return false
1373 }
1374
1375
1376
1377 func overlap(offset1, size1, offset2, size2 int64) bool {
1378 if offset1 >= offset2 && offset2+size2 > offset1 {
1379 return true
1380 }
1381 if offset2 >= offset1 && offset1+size1 > offset2 {
1382 return true
1383 }
1384 return false
1385 }
1386
1387
1388
1389
1390 func ZeroUpper32Bits(x *Value) bool { return zeroUpperBits(x, 32, 3) }
1391
1392
1393 func ZeroUpper48Bits(x *Value) bool { return zeroUpperBits(x, 48, 3) }
1394
1395
1396 func ZeroUpper56Bits(x *Value) bool { return zeroUpperBits(x, 56, 3) }
1397
1398
1399
1400
1401
1402
1403 func zeroUpperBits(x *Value, bits int64, depth int) bool {
1404 if x.Type.IsSigned() && 8*x.Type.Size() <= 64-bits {
1405
1406
1407
1408
1409
1410 return false
1411 }
1412 if int64(opcodeTable[x.Op].zeroUpperBits) >= bits {
1413 return true
1414 }
1415 switch x.Op {
1416 case OpAMD64MOVQconst, OpAMD64MOVLconst:
1417
1418
1419
1420 return uint64(x.AuxInt)>>(64-bits) == 0
1421 case OpArg:
1422
1423
1424 return 8*x.Type.Size() == 64-bits && x.Block.Func.Config.arch == "amd64"
1425 case OpSelect0, OpSelect1:
1426
1427
1428
1429
1430
1431 return int64(opcodeTable[x.Args[0].Op].zeroUpperBits) >= bits
1432 case OpPhi:
1433
1434
1435 if depth <= 0 {
1436 return false
1437 }
1438 for i := range x.Args {
1439 if !zeroUpperBits(x.Args[i], bits, depth-1) {
1440 return false
1441 }
1442 }
1443 return true
1444 }
1445 return false
1446 }
1447
1448 func isInlinableMemclr(c *Config, sz int64) bool {
1449 if sz < 0 {
1450 return false
1451 }
1452
1453
1454 switch c.arch {
1455 case "amd64", "arm64":
1456 return true
1457 case "ppc64le", "ppc64", "loong64":
1458 return sz < 512
1459 }
1460 return false
1461 }
1462
1463
1464
1465
1466
1467
1468 func isInlinableMemmove(dst, src *Value, sz int64, c *Config) bool {
1469
1470
1471
1472
1473 switch c.arch {
1474 case "amd64":
1475 return sz <= 16 || (sz < 1024 && disjoint1(dst, sz, src, sz))
1476 case "arm64":
1477 return sz <= 64 || (sz <= 1024 && disjoint1(dst, sz, src, sz))
1478 case "loong64":
1479 return sz <= 16 || (sz <= 64 && disjoint1(dst, sz, src, sz))
1480 case "386":
1481 return sz <= 8
1482 case "s390x", "ppc64", "ppc64le":
1483 return sz <= 8 || disjoint1(dst, sz, src, sz)
1484 case "arm", "mips", "mips64", "mipsle", "mips64le":
1485 return sz <= 4
1486 }
1487 return false
1488 }
1489 func IsInlinableMemmove(dst, src *Value, sz int64, c *Config) bool {
1490 return isInlinableMemmove(dst, src, sz, c)
1491 }
1492
1493
1494
1495
1496 func logLargeCopy(v *Value, s int64) bool {
1497 if s < 128 {
1498 return true
1499 }
1500 if logopt.Enabled() {
1501 logopt.LogOpt(v.Pos, "copy", "lower", v.Block.Func.Name, fmt.Sprintf("%d bytes", s))
1502 }
1503 return true
1504 }
1505 func LogLargeCopy(funcName string, pos src.XPos, s int64) {
1506 if s < 128 {
1507 return
1508 }
1509 if logopt.Enabled() {
1510 logopt.LogOpt(pos, "copy", "lower", funcName, fmt.Sprintf("%d bytes", s))
1511 }
1512 }
1513
1514
1515
1516 func hasSmallRotate(c *Config) bool {
1517 switch c.arch {
1518 case "amd64", "386":
1519 return true
1520 default:
1521 return false
1522 }
1523 }
1524
1525 func supportsPPC64PCRel() bool {
1526
1527
1528 return buildcfg.GOPPC64 >= 10 && buildcfg.GOOS == "linux"
1529 }
1530
1531 func newPPC64ShiftAuxInt(sh, mb, me, sz int64) int32 {
1532 if sh < 0 || sh >= sz {
1533 panic("PPC64 shift arg sh out of range")
1534 }
1535 if mb < 0 || mb >= sz {
1536 panic("PPC64 shift arg mb out of range")
1537 }
1538 if me < 0 || me >= sz {
1539 panic("PPC64 shift arg me out of range")
1540 }
1541 return int32(sh<<16 | mb<<8 | me)
1542 }
1543
1544 func GetPPC64Shiftsh(auxint int64) int64 {
1545 return int64(int8(auxint >> 16))
1546 }
1547
1548 func GetPPC64Shiftmb(auxint int64) int64 {
1549 return int64(int8(auxint >> 8))
1550 }
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561 func isPPC64WordRotateMask(v64 int64) bool {
1562
1563 v := uint32(v64)
1564 vp := (v & -v) + v
1565
1566 vn := ^v
1567 vpn := (vn & -vn) + vn
1568 return (v&vp == 0 || vn&vpn == 0) && v != 0
1569 }
1570
1571
1572
1573
1574 func isPPC64WordRotateMaskNonWrapping(v64 int64) bool {
1575
1576 v := uint32(v64)
1577 vp := (v & -v) + v
1578 return (v&vp == 0) && v != 0 && uint64(uint32(v64)) == uint64(v64)
1579 }
1580
1581
1582
1583
1584 func encodePPC64RotateMask(rotate, mask, nbits int64) int64 {
1585 var mb, me, mbn, men int
1586
1587
1588 if mask == 0 || ^mask == 0 || rotate >= nbits {
1589 panic(fmt.Sprintf("invalid PPC64 rotate mask: %x %d %d", uint64(mask), rotate, nbits))
1590 } else if nbits == 32 {
1591 mb = bits.LeadingZeros32(uint32(mask))
1592 me = 32 - bits.TrailingZeros32(uint32(mask))
1593 mbn = bits.LeadingZeros32(^uint32(mask))
1594 men = 32 - bits.TrailingZeros32(^uint32(mask))
1595 } else {
1596 mb = bits.LeadingZeros64(uint64(mask))
1597 me = 64 - bits.TrailingZeros64(uint64(mask))
1598 mbn = bits.LeadingZeros64(^uint64(mask))
1599 men = 64 - bits.TrailingZeros64(^uint64(mask))
1600 }
1601
1602 if mb == 0 && me == int(nbits) {
1603
1604 mb, me = men, mbn
1605 }
1606
1607 return int64(me) | int64(mb<<8) | rotate<<16 | nbits<<24
1608 }
1609
1610
1611
1612
1613
1614
1615 func mergePPC64RLDICLandSRDconst(encoded, s int64) int64 {
1616 mb := s
1617 r := 64 - s
1618
1619 if (encoded>>8)&0xFF < mb {
1620 encoded = (encoded &^ 0xFF00) | mb<<8
1621 }
1622
1623 if (encoded & 0xFF0000) != 0 {
1624 panic("non-zero rotate")
1625 }
1626 return encoded | r<<16
1627 }
1628
1629
1630
1631 func DecodePPC64RotateMask(sauxint int64) (rotate, mb, me int64, mask uint64) {
1632 auxint := uint64(sauxint)
1633 rotate = int64((auxint >> 16) & 0xFF)
1634 mb = int64((auxint >> 8) & 0xFF)
1635 me = int64((auxint >> 0) & 0xFF)
1636 nbits := int64((auxint >> 24) & 0xFF)
1637 mask = ((1 << uint(nbits-mb)) - 1) ^ ((1 << uint(nbits-me)) - 1)
1638 if mb > me {
1639 mask = ^mask
1640 }
1641 if nbits == 32 {
1642 mask = uint64(uint32(mask))
1643 }
1644
1645
1646
1647 me = (me - 1) & (nbits - 1)
1648 return
1649 }
1650
1651
1652
1653
1654 func isPPC64ValidShiftMask(v int64) bool {
1655 if (v != 0) && ((v+1)&v) == 0 {
1656 return true
1657 }
1658 return false
1659 }
1660
1661 func getPPC64ShiftMaskLength(v int64) int64 {
1662 return int64(bits.Len64(uint64(v)))
1663 }
1664
1665
1666
1667 func mergePPC64RShiftMask(m, s, nbits int64) int64 {
1668 smask := uint64((1<<uint(nbits))-1) >> uint(s)
1669 return m & int64(smask)
1670 }
1671
1672
1673 func mergePPC64AndSrwi(m, s int64) int64 {
1674 mask := mergePPC64RShiftMask(m, s, 32)
1675 if !isPPC64WordRotateMask(mask) {
1676 return 0
1677 }
1678 return encodePPC64RotateMask((32-s)&31, mask, 32)
1679 }
1680
1681
1682 func mergePPC64AndSrdi(m, s int64) int64 {
1683 mask := mergePPC64RShiftMask(m, s, 64)
1684
1685
1686 rv := bits.RotateLeft64(0xFFFFFFFF00000000, -int(s))
1687 if rv&uint64(mask) != 0 {
1688 return 0
1689 }
1690 if !isPPC64WordRotateMaskNonWrapping(mask) {
1691 return 0
1692 }
1693 return encodePPC64RotateMask((32-s)&31, mask, 32)
1694 }
1695
1696
1697 func mergePPC64AndSldi(m, s int64) int64 {
1698 mask := -1 << s & m
1699
1700
1701 rv := bits.RotateLeft64(0xFFFFFFFF00000000, int(s))
1702 if rv&uint64(mask) != 0 {
1703 return 0
1704 }
1705 if !isPPC64WordRotateMaskNonWrapping(mask) {
1706 return 0
1707 }
1708 return encodePPC64RotateMask(s&31, mask, 32)
1709 }
1710
1711
1712
1713 func mergePPC64ClrlsldiSrw(sld, srw int64) int64 {
1714 mask_1 := uint64(0xFFFFFFFF >> uint(srw))
1715
1716 mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(sld))
1717
1718
1719 mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(sld))
1720
1721 r_1 := 32 - srw
1722 r_2 := GetPPC64Shiftsh(sld)
1723 r_3 := (r_1 + r_2) & 31
1724
1725 if uint64(uint32(mask_3)) != mask_3 || mask_3 == 0 {
1726 return 0
1727 }
1728 return encodePPC64RotateMask(r_3, int64(mask_3), 32)
1729 }
1730
1731
1732
1733 func mergePPC64ClrlsldiSrd(sld, srd int64) int64 {
1734 mask_1 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(srd)
1735
1736 mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(sld))
1737
1738
1739 mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(sld))
1740
1741 r_1 := 64 - srd
1742 r_2 := GetPPC64Shiftsh(sld)
1743 r_3 := (r_1 + r_2) & 63
1744
1745 if uint64(uint32(mask_3)) != mask_3 || mask_3 == 0 {
1746 return 0
1747 }
1748
1749 v1 := bits.RotateLeft64(0xFFFFFFFF00000000, int(r_3))
1750 if v1&mask_3 != 0 {
1751 return 0
1752 }
1753 return encodePPC64RotateMask(r_3&31, int64(mask_3), 32)
1754 }
1755
1756
1757
1758 func mergePPC64ClrlsldiRlwinm(sld int32, rlw int64) int64 {
1759 r_1, _, _, mask_1 := DecodePPC64RotateMask(rlw)
1760
1761 mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(int64(sld)))
1762
1763
1764 mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(int64(sld)))
1765 r_2 := GetPPC64Shiftsh(int64(sld))
1766 r_3 := (r_1 + r_2) & 31
1767
1768
1769 if !isPPC64WordRotateMask(int64(mask_3)) || uint64(uint32(mask_3)) != mask_3 {
1770 return 0
1771 }
1772 return encodePPC64RotateMask(r_3, int64(mask_3), 32)
1773 }
1774
1775
1776
1777 func mergePPC64AndRlwinm(mask uint32, rlw int64) int64 {
1778 r, _, _, mask_rlw := DecodePPC64RotateMask(rlw)
1779 mask_out := (mask_rlw & uint64(mask))
1780
1781
1782 if !isPPC64WordRotateMask(int64(mask_out)) {
1783 return 0
1784 }
1785 return encodePPC64RotateMask(r, int64(mask_out), 32)
1786 }
1787
1788
1789
1790 func mergePPC64MovwzregRlwinm(rlw int64) int64 {
1791 _, mb, me, _ := DecodePPC64RotateMask(rlw)
1792 if mb > me {
1793 return 0
1794 }
1795 return rlw
1796 }
1797
1798
1799
1800 func mergePPC64RlwinmAnd(rlw int64, mask uint32) int64 {
1801 r, _, _, mask_rlw := DecodePPC64RotateMask(rlw)
1802
1803
1804 r_mask := bits.RotateLeft32(mask, int(r))
1805
1806 mask_out := (mask_rlw & uint64(r_mask))
1807
1808
1809 if !isPPC64WordRotateMask(int64(mask_out)) {
1810 return 0
1811 }
1812 return encodePPC64RotateMask(r, int64(mask_out), 32)
1813 }
1814
1815
1816
1817 func mergePPC64SldiRlwinm(sldi, rlw int64) int64 {
1818 r_1, mb, me, mask_1 := DecodePPC64RotateMask(rlw)
1819 if mb > me || mb < sldi {
1820
1821
1822 return 0
1823 }
1824
1825 mask_3 := mask_1 << sldi
1826 r_3 := (r_1 + sldi) & 31
1827
1828
1829 if uint64(uint32(mask_3)) != mask_3 {
1830 return 0
1831 }
1832 return encodePPC64RotateMask(r_3, int64(mask_3), 32)
1833 }
1834
1835
1836
1837 func mergePPC64SldiSrw(sld, srw int64) int64 {
1838 if sld > srw || srw >= 32 {
1839 return 0
1840 }
1841 mask_r := uint32(0xFFFFFFFF) >> uint(srw)
1842 mask_l := uint32(0xFFFFFFFF) >> uint(sld)
1843 mask := (mask_r & mask_l) << uint(sld)
1844 return encodePPC64RotateMask((32-srw+sld)&31, int64(mask), 32)
1845 }
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872 func convertPPC64OpToOpCC(op *Value) *Value {
1873 ccOpMap := map[Op]Op{
1874 OpPPC64ADD: OpPPC64ADDCC,
1875 OpPPC64ADDconst: OpPPC64ADDCCconst,
1876 OpPPC64AND: OpPPC64ANDCC,
1877 OpPPC64ANDN: OpPPC64ANDNCC,
1878 OpPPC64ANDconst: OpPPC64ANDCCconst,
1879 OpPPC64CNTLZD: OpPPC64CNTLZDCC,
1880 OpPPC64MULHDU: OpPPC64MULHDUCC,
1881 OpPPC64NEG: OpPPC64NEGCC,
1882 OpPPC64NOR: OpPPC64NORCC,
1883 OpPPC64OR: OpPPC64ORCC,
1884 OpPPC64RLDICL: OpPPC64RLDICLCC,
1885 OpPPC64SUB: OpPPC64SUBCC,
1886 OpPPC64XOR: OpPPC64XORCC,
1887 }
1888 b := op.Block
1889 opCC := b.NewValue0I(op.Pos, ccOpMap[op.Op], types.NewTuple(op.Type, types.TypeFlags), op.AuxInt)
1890 opCC.AddArgs(op.Args...)
1891 op.reset(OpSelect0)
1892 op.AddArgs(opCC)
1893 return op
1894 }
1895
1896
1897 func convertPPC64RldiclAndccconst(sauxint int64) int64 {
1898 r, _, _, mask := DecodePPC64RotateMask(sauxint)
1899 if r != 0 || mask&0xFFFF != mask {
1900 return 0
1901 }
1902 return int64(mask)
1903 }
1904
1905
1906 func rotateLeft32(v, rotate int64) int64 {
1907 return int64(bits.RotateLeft32(uint32(v), int(rotate)))
1908 }
1909
1910 func rotateRight64(v, rotate int64) int64 {
1911 return int64(bits.RotateLeft64(uint64(v), int(-rotate)))
1912 }
1913
1914
1915 func armBFAuxInt(lsb, width int64) arm64BitField {
1916 if lsb < 0 || lsb > 63 {
1917 panic("ARM(64) bit field lsb constant out of range")
1918 }
1919 if width < 1 || lsb+width > 64 {
1920 panic("ARM(64) bit field width constant out of range")
1921 }
1922 return arm64BitField(width | lsb<<8)
1923 }
1924
1925
1926 func (bfc arm64BitField) lsb() int64 {
1927 return int64(uint64(bfc) >> 8)
1928 }
1929
1930
1931 func (bfc arm64BitField) width() int64 {
1932 return int64(bfc) & 0xff
1933 }
1934
1935
1936 func isARM64BFMask(lsb, mask, rshift int64) bool {
1937 shiftedMask := int64(uint64(mask) >> uint64(rshift))
1938 return shiftedMask != 0 && isPowerOfTwo(shiftedMask+1) && nto(shiftedMask)+lsb < 64
1939 }
1940
1941
1942 func arm64BFWidth(mask, rshift int64) int64 {
1943 shiftedMask := int64(uint64(mask) >> uint64(rshift))
1944 if shiftedMask == 0 {
1945 panic("ARM64 BF mask is zero")
1946 }
1947 return nto(shiftedMask)
1948 }
1949
1950
1951 func arm64ConditionalParamsAuxInt(cond Op, nzcv uint8) arm64ConditionalParams {
1952 if cond < OpARM64Equal || cond > OpARM64GreaterEqualU {
1953 panic("Wrong conditional operation")
1954 }
1955 if nzcv&0x0f != nzcv {
1956 panic("Wrong value of NZCV flag")
1957 }
1958 return arm64ConditionalParams{cond, nzcv, 0, false}
1959 }
1960
1961
1962 func arm64ConditionalParamsAuxIntWithValue(cond Op, nzcv uint8, value uint8) arm64ConditionalParams {
1963 if value&0x1f != value {
1964 panic("Wrong value of constant")
1965 }
1966 params := arm64ConditionalParamsAuxInt(cond, nzcv)
1967 params.constValue = value
1968 params.ind = true
1969 return params
1970 }
1971
1972
1973 func (condParams arm64ConditionalParams) Cond() Op {
1974 return condParams.cond
1975 }
1976
1977
1978 func (condParams arm64ConditionalParams) Nzcv() int64 {
1979 return int64(condParams.nzcv)
1980 }
1981
1982
1983 func (condParams arm64ConditionalParams) ConstValue() (int64, bool) {
1984 return int64(condParams.constValue), condParams.ind
1985 }
1986
1987
1988
1989
1990 func registerizable(b *Block, typ *types.Type) bool {
1991 if typ.IsPtrShaped() || typ.IsFloat() || typ.IsBoolean() {
1992 return true
1993 }
1994 if typ.IsInteger() {
1995 return typ.Size() <= b.Func.Config.RegSize
1996 }
1997 return false
1998 }
1999
2000
2001 func needRaceCleanup(sym *AuxCall, v *Value) bool {
2002 f := v.Block.Func
2003 if !f.Config.Race {
2004 return false
2005 }
2006 if !isSameCall(sym, "runtime.racefuncenter") && !isSameCall(sym, "runtime.racefuncexit") {
2007 return false
2008 }
2009 for _, b := range f.Blocks {
2010 for _, v := range b.Values {
2011 switch v.Op {
2012 case OpStaticCall, OpStaticLECall:
2013
2014
2015 s := v.Aux.(*AuxCall).Fn.String()
2016 switch s {
2017 case "runtime.racefuncenter", "runtime.racefuncexit",
2018 "runtime.panicdivide", "runtime.panicwrap",
2019 "runtime.panicshift":
2020 continue
2021 }
2022
2023
2024 return false
2025 case OpPanicBounds, OpPanicExtend:
2026
2027 case OpClosureCall, OpInterCall, OpClosureLECall, OpInterLECall:
2028
2029 return false
2030 }
2031 }
2032 }
2033 if isSameCall(sym, "runtime.racefuncenter") {
2034
2035
2036 if v.Args[0].Op != OpStore {
2037 if v.Op == OpStaticLECall {
2038
2039 return true
2040 }
2041 return false
2042 }
2043 mem := v.Args[0].Args[2]
2044 v.Args[0].reset(OpCopy)
2045 v.Args[0].AddArg(mem)
2046 }
2047 return true
2048 }
2049
2050
2051 func symIsRO(sym Sym) bool {
2052 lsym := sym.(*obj.LSym)
2053 return lsym.Type == objabi.SRODATA && len(lsym.R) == 0
2054 }
2055
2056
2057 func symIsROZero(sym Sym) bool {
2058 lsym := sym.(*obj.LSym)
2059 if lsym.Type != objabi.SRODATA || len(lsym.R) != 0 {
2060 return false
2061 }
2062 for _, b := range lsym.P {
2063 if b != 0 {
2064 return false
2065 }
2066 }
2067 return true
2068 }
2069
2070
2071
2072 func isFixedLoad(v *Value, sym Sym, off int64) bool {
2073 lsym := sym.(*obj.LSym)
2074 if (v.Type.IsPtrShaped() || v.Type.IsUintptr()) && lsym.Type == objabi.SRODATA {
2075 for _, r := range lsym.R {
2076 if (r.Type == objabi.R_ADDR || r.Type == objabi.R_WEAKADDR) && int64(r.Off) == off && r.Add == 0 {
2077 return true
2078 }
2079 }
2080 return false
2081 }
2082
2083 if ti := lsym.TypeInfo(); ti != nil {
2084
2085
2086
2087
2088 t := ti.Type.(*types.Type)
2089
2090 for _, f := range rttype.Type.Fields() {
2091 if f.Offset == off && copyCompatibleType(v.Type, f.Type) {
2092 switch f.Sym.Name {
2093 case "Size_", "PtrBytes", "Hash", "Kind_", "GCData":
2094 return true
2095 default:
2096
2097 return false
2098 }
2099 }
2100 }
2101
2102 if t.IsPtr() && off == rttype.PtrType.OffsetOf("Elem") {
2103 return true
2104 }
2105
2106 return false
2107 }
2108
2109 return false
2110 }
2111
2112
2113 func rewriteFixedLoad(v *Value, sym Sym, sb *Value, off int64) *Value {
2114 b := v.Block
2115 f := b.Func
2116
2117 lsym := sym.(*obj.LSym)
2118 if (v.Type.IsPtrShaped() || v.Type.IsUintptr()) && lsym.Type == objabi.SRODATA {
2119 for _, r := range lsym.R {
2120 if (r.Type == objabi.R_ADDR || r.Type == objabi.R_WEAKADDR) && int64(r.Off) == off && r.Add == 0 {
2121 if strings.HasPrefix(r.Sym.Name, "type:") {
2122
2123
2124
2125
2126
2127 reflectdata.MarkTypeSymUsedInInterface(r.Sym, f.fe.Func().Linksym())
2128 } else if strings.HasPrefix(r.Sym.Name, "go:itab") {
2129
2130
2131 reflectdata.MarkTypeSymUsedInInterface(r.Sym, f.fe.Func().Linksym())
2132 }
2133 v.reset(OpAddr)
2134 v.Aux = symToAux(r.Sym)
2135 v.AddArg(sb)
2136 return v
2137 }
2138 }
2139 base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
2140 }
2141
2142 if ti := lsym.TypeInfo(); ti != nil {
2143
2144
2145
2146
2147 t := ti.Type.(*types.Type)
2148
2149 ptrSizedOpConst := OpConst64
2150 if f.Config.PtrSize == 4 {
2151 ptrSizedOpConst = OpConst32
2152 }
2153
2154 for _, f := range rttype.Type.Fields() {
2155 if f.Offset == off && copyCompatibleType(v.Type, f.Type) {
2156 switch f.Sym.Name {
2157 case "Size_":
2158 v.reset(ptrSizedOpConst)
2159 v.AuxInt = t.Size()
2160 return v
2161 case "PtrBytes":
2162 v.reset(ptrSizedOpConst)
2163 v.AuxInt = types.PtrDataSize(t)
2164 return v
2165 case "Hash":
2166 v.reset(OpConst32)
2167 v.AuxInt = int64(int32(types.TypeHash(t)))
2168 return v
2169 case "Kind_":
2170 v.reset(OpConst8)
2171 v.AuxInt = int64(int8(reflectdata.ABIKindOfType(t)))
2172 return v
2173 case "GCData":
2174 gcdata, _ := reflectdata.GCSym(t, true)
2175 v.reset(OpAddr)
2176 v.Aux = symToAux(gcdata)
2177 v.AddArg(sb)
2178 return v
2179 default:
2180 base.Fatalf("unknown field %s for fixedLoad of %s at offset %d", f.Sym.Name, lsym.Name, off)
2181 }
2182 }
2183 }
2184
2185 if t.IsPtr() && off == rttype.PtrType.OffsetOf("Elem") {
2186 elemSym := reflectdata.TypeLinksym(t.Elem())
2187 reflectdata.MarkTypeSymUsedInInterface(elemSym, f.fe.Func().Linksym())
2188 v.reset(OpAddr)
2189 v.Aux = symToAux(elemSym)
2190 v.AddArg(sb)
2191 return v
2192 }
2193
2194 base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
2195 }
2196
2197 base.Fatalf("fixedLoad data not known for %s:%d", sym, off)
2198 return nil
2199 }
2200
2201
2202 func read8(sym Sym, off int64) uint8 {
2203 lsym := sym.(*obj.LSym)
2204 if off >= int64(len(lsym.P)) || off < 0 {
2205
2206
2207
2208
2209 return 0
2210 }
2211 return lsym.P[off]
2212 }
2213
2214
2215 func read16(sym Sym, off int64, byteorder binary.ByteOrder) uint16 {
2216 lsym := sym.(*obj.LSym)
2217
2218
2219 var src []byte
2220 if 0 <= off && off < int64(len(lsym.P)) {
2221 src = lsym.P[off:]
2222 }
2223 buf := make([]byte, 2)
2224 copy(buf, src)
2225 return byteorder.Uint16(buf)
2226 }
2227
2228
2229 func read32(sym Sym, off int64, byteorder binary.ByteOrder) uint32 {
2230 lsym := sym.(*obj.LSym)
2231 var src []byte
2232 if 0 <= off && off < int64(len(lsym.P)) {
2233 src = lsym.P[off:]
2234 }
2235 buf := make([]byte, 4)
2236 copy(buf, src)
2237 return byteorder.Uint32(buf)
2238 }
2239
2240
2241 func read64(sym Sym, off int64, byteorder binary.ByteOrder) uint64 {
2242 lsym := sym.(*obj.LSym)
2243 var src []byte
2244 if 0 <= off && off < int64(len(lsym.P)) {
2245 src = lsym.P[off:]
2246 }
2247 buf := make([]byte, 8)
2248 copy(buf, src)
2249 return byteorder.Uint64(buf)
2250 }
2251
2252
2253 func sequentialAddresses(x, y *Value, n int64) bool {
2254 if x == y && n == 0 {
2255 return true
2256 }
2257 if x.Op == Op386ADDL && y.Op == Op386LEAL1 && y.AuxInt == n && y.Aux == nil &&
2258 (x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
2259 x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
2260 return true
2261 }
2262 if x.Op == Op386LEAL1 && y.Op == Op386LEAL1 && y.AuxInt == x.AuxInt+n && x.Aux == y.Aux &&
2263 (x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
2264 x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
2265 return true
2266 }
2267 if x.Op == OpAMD64ADDQ && y.Op == OpAMD64LEAQ1 && y.AuxInt == n && y.Aux == nil &&
2268 (x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
2269 x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
2270 return true
2271 }
2272 if x.Op == OpAMD64LEAQ1 && y.Op == OpAMD64LEAQ1 && y.AuxInt == x.AuxInt+n && x.Aux == y.Aux &&
2273 (x.Args[0] == y.Args[0] && x.Args[1] == y.Args[1] ||
2274 x.Args[0] == y.Args[1] && x.Args[1] == y.Args[0]) {
2275 return true
2276 }
2277 return false
2278 }
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292 type flagConstant uint8
2293
2294
2295 func (fc flagConstant) N() bool {
2296 return fc&1 != 0
2297 }
2298
2299
2300 func (fc flagConstant) Z() bool {
2301 return fc&2 != 0
2302 }
2303
2304
2305
2306 func (fc flagConstant) C() bool {
2307 return fc&4 != 0
2308 }
2309
2310
2311 func (fc flagConstant) V() bool {
2312 return fc&8 != 0
2313 }
2314
2315 func (fc flagConstant) eq() bool {
2316 return fc.Z()
2317 }
2318 func (fc flagConstant) ne() bool {
2319 return !fc.Z()
2320 }
2321 func (fc flagConstant) lt() bool {
2322 return fc.N() != fc.V()
2323 }
2324 func (fc flagConstant) le() bool {
2325 return fc.Z() || fc.lt()
2326 }
2327 func (fc flagConstant) gt() bool {
2328 return !fc.Z() && fc.ge()
2329 }
2330 func (fc flagConstant) ge() bool {
2331 return fc.N() == fc.V()
2332 }
2333 func (fc flagConstant) ult() bool {
2334 return !fc.C()
2335 }
2336 func (fc flagConstant) ule() bool {
2337 return fc.Z() || fc.ult()
2338 }
2339 func (fc flagConstant) ugt() bool {
2340 return !fc.Z() && fc.uge()
2341 }
2342 func (fc flagConstant) uge() bool {
2343 return fc.C()
2344 }
2345
2346 func (fc flagConstant) ltNoov() bool {
2347 return fc.lt() && !fc.V()
2348 }
2349 func (fc flagConstant) leNoov() bool {
2350 return fc.le() && !fc.V()
2351 }
2352 func (fc flagConstant) gtNoov() bool {
2353 return fc.gt() && !fc.V()
2354 }
2355 func (fc flagConstant) geNoov() bool {
2356 return fc.ge() && !fc.V()
2357 }
2358
2359 func (fc flagConstant) String() string {
2360 return fmt.Sprintf("N=%v,Z=%v,C=%v,V=%v", fc.N(), fc.Z(), fc.C(), fc.V())
2361 }
2362
2363 type flagConstantBuilder struct {
2364 N bool
2365 Z bool
2366 C bool
2367 V bool
2368 }
2369
2370 func (fcs flagConstantBuilder) encode() flagConstant {
2371 var fc flagConstant
2372 if fcs.N {
2373 fc |= 1
2374 }
2375 if fcs.Z {
2376 fc |= 2
2377 }
2378 if fcs.C {
2379 fc |= 4
2380 }
2381 if fcs.V {
2382 fc |= 8
2383 }
2384 return fc
2385 }
2386
2387
2388
2389
2390
2391
2392 func addFlags64(x, y int64) flagConstant {
2393 var fcb flagConstantBuilder
2394 fcb.Z = x+y == 0
2395 fcb.N = x+y < 0
2396 fcb.C = uint64(x+y) < uint64(x)
2397 fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
2398 return fcb.encode()
2399 }
2400
2401
2402 func subFlags64(x, y int64) flagConstant {
2403 var fcb flagConstantBuilder
2404 fcb.Z = x-y == 0
2405 fcb.N = x-y < 0
2406 fcb.C = uint64(y) <= uint64(x)
2407 fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
2408 return fcb.encode()
2409 }
2410
2411
2412 func addFlags32(x, y int32) flagConstant {
2413 var fcb flagConstantBuilder
2414 fcb.Z = x+y == 0
2415 fcb.N = x+y < 0
2416 fcb.C = uint32(x+y) < uint32(x)
2417 fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
2418 return fcb.encode()
2419 }
2420
2421
2422 func subFlags32(x, y int32) flagConstant {
2423 var fcb flagConstantBuilder
2424 fcb.Z = x-y == 0
2425 fcb.N = x-y < 0
2426 fcb.C = uint32(y) <= uint32(x)
2427 fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
2428 return fcb.encode()
2429 }
2430
2431
2432
2433 func logicFlags64(x int64) flagConstant {
2434 var fcb flagConstantBuilder
2435 fcb.Z = x == 0
2436 fcb.N = x < 0
2437 return fcb.encode()
2438 }
2439
2440
2441
2442 func logicFlags32(x int32) flagConstant {
2443 var fcb flagConstantBuilder
2444 fcb.Z = x == 0
2445 fcb.N = x < 0
2446 return fcb.encode()
2447 }
2448
2449 func makeJumpTableSym(b *Block) *obj.LSym {
2450 s := base.Ctxt.Lookup(fmt.Sprintf("%s.jump%d", b.Func.fe.Func().LSym.Name, b.ID))
2451
2452 s.Set(obj.AttrStatic, true)
2453 return s
2454 }
2455
2456
2457
2458 func canRotate(c *Config, bits int64) bool {
2459 if bits > c.PtrSize*8 {
2460
2461 return false
2462 }
2463 switch c.arch {
2464 case "386", "amd64", "arm64", "loong64", "riscv64":
2465 return true
2466 case "arm", "s390x", "ppc64", "ppc64le", "wasm":
2467 return bits >= 32
2468 default:
2469 return false
2470 }
2471 }
2472
2473
2474 func isARM64bitcon(x uint64) bool {
2475 if x == 1<<64-1 || x == 0 {
2476 return false
2477 }
2478
2479 switch {
2480 case x != x>>32|x<<32:
2481
2482
2483 case x != x>>16|x<<48:
2484
2485 x = uint64(int64(int32(x)))
2486 case x != x>>8|x<<56:
2487
2488 x = uint64(int64(int16(x)))
2489 case x != x>>4|x<<60:
2490
2491 x = uint64(int64(int8(x)))
2492 default:
2493
2494
2495
2496
2497
2498 return true
2499 }
2500 return sequenceOfOnes(x) || sequenceOfOnes(^x)
2501 }
2502
2503
2504 func sequenceOfOnes(x uint64) bool {
2505 y := x & -x
2506 y += x
2507 return (y-1)&y == 0
2508 }
2509
2510
2511 func isARM64addcon(v int64) bool {
2512
2513 if v < 0 {
2514 return false
2515 }
2516 if (v & 0xFFF) == 0 {
2517 v >>= 12
2518 }
2519 return v <= 0xFFF
2520 }
2521
2522
2523
2524
2525 func setPos(v *Value, pos src.XPos) bool {
2526 v.Pos = pos
2527 return true
2528 }
2529
2530
2531
2532
2533 func isNonNegative(v *Value) bool {
2534 if !v.Type.IsInteger() {
2535 v.Fatalf("isNonNegative bad type: %v", v.Type)
2536 }
2537
2538
2539
2540
2541 switch v.Op {
2542 case OpConst64:
2543 return v.AuxInt >= 0
2544
2545 case OpConst32:
2546 return int32(v.AuxInt) >= 0
2547
2548 case OpConst16:
2549 return int16(v.AuxInt) >= 0
2550
2551 case OpConst8:
2552 return int8(v.AuxInt) >= 0
2553
2554 case OpStringLen, OpSliceLen, OpSliceCap,
2555 OpZeroExt8to64, OpZeroExt16to64, OpZeroExt32to64,
2556 OpZeroExt8to32, OpZeroExt16to32, OpZeroExt8to16,
2557 OpCtz64, OpCtz32, OpCtz16, OpCtz8,
2558 OpCtz64NonZero, OpCtz32NonZero, OpCtz16NonZero, OpCtz8NonZero,
2559 OpBitLen64, OpBitLen32, OpBitLen16, OpBitLen8:
2560 return true
2561
2562 case OpRsh64Ux64, OpRsh32Ux64:
2563 by := v.Args[1]
2564 return by.Op == OpConst64 && by.AuxInt > 0
2565
2566 case OpRsh64x64, OpRsh32x64, OpRsh8x64, OpRsh16x64, OpRsh32x32, OpRsh64x32,
2567 OpSignExt32to64, OpSignExt16to64, OpSignExt8to64, OpSignExt16to32, OpSignExt8to32:
2568 return isNonNegative(v.Args[0])
2569
2570 case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
2571 return isNonNegative(v.Args[0]) || isNonNegative(v.Args[1])
2572
2573 case OpMod64, OpMod32, OpMod16, OpMod8,
2574 OpDiv64, OpDiv32, OpDiv16, OpDiv8,
2575 OpOr64, OpOr32, OpOr16, OpOr8,
2576 OpXor64, OpXor32, OpXor16, OpXor8:
2577 return isNonNegative(v.Args[0]) && isNonNegative(v.Args[1])
2578
2579
2580
2581 }
2582 return false
2583 }
2584
2585 func rewriteStructLoad(v *Value) *Value {
2586 b := v.Block
2587 ptr := v.Args[0]
2588 mem := v.Args[1]
2589
2590 t := v.Type
2591 args := make([]*Value, t.NumFields())
2592 for i := range args {
2593 ft := t.FieldType(i)
2594 addr := b.NewValue1I(v.Pos, OpOffPtr, ft.PtrTo(), t.FieldOff(i), ptr)
2595 args[i] = b.NewValue2(v.Pos, OpLoad, ft, addr, mem)
2596 }
2597
2598 v.reset(OpStructMake)
2599 v.AddArgs(args...)
2600 return v
2601 }
2602
2603 func rewriteStructStore(v *Value) *Value {
2604 b := v.Block
2605 dst := v.Args[0]
2606 x := v.Args[1]
2607 if x.Op != OpStructMake {
2608 base.Fatalf("invalid struct store: %v", x)
2609 }
2610 mem := v.Args[2]
2611
2612 t := x.Type
2613 for i, arg := range x.Args {
2614 ft := t.FieldType(i)
2615
2616 addr := b.NewValue1I(v.Pos, OpOffPtr, ft.PtrTo(), t.FieldOff(i), dst)
2617 mem = b.NewValue3A(v.Pos, OpStore, types.TypeMem, typeToAux(ft), addr, arg, mem)
2618 }
2619
2620 return mem
2621 }
2622
2623
2624
2625
2626 func isDirectAndComparableType(v *Value) bool {
2627 return isDirectAndComparableType1(v)
2628 }
2629
2630
2631 func isDirectAndComparableType1(v *Value) bool {
2632 switch v.Op {
2633 case OpITab:
2634 return isDirectAndComparableType2(v.Args[0])
2635 case OpAddr:
2636 lsym := v.Aux.(*obj.LSym)
2637 if ti := lsym.TypeInfo(); ti != nil {
2638 t := ti.Type.(*types.Type)
2639 return types.IsDirectIface(t) && types.IsComparable(t)
2640 }
2641 }
2642 return false
2643 }
2644
2645
2646 func isDirectAndComparableType2(v *Value) bool {
2647 switch v.Op {
2648 case OpIMake:
2649 return isDirectAndComparableType1(v.Args[0])
2650 }
2651 return false
2652 }
2653
2654
2655
2656
2657 func isDirectAndComparableIface(v *Value) bool {
2658 return isDirectAndComparableIface1(v, 9)
2659 }
2660
2661
2662 func isDirectAndComparableIface1(v *Value, depth int) bool {
2663 if depth == 0 {
2664 return false
2665 }
2666 switch v.Op {
2667 case OpITab:
2668 return isDirectAndComparableIface2(v.Args[0], depth-1)
2669 case OpAddr:
2670 lsym := v.Aux.(*obj.LSym)
2671 if ii := lsym.ItabInfo(); ii != nil {
2672 t := ii.Type.(*types.Type)
2673 return types.IsDirectIface(t) && types.IsComparable(t)
2674 }
2675 case OpConstNil:
2676
2677
2678 return true
2679 }
2680 return false
2681 }
2682
2683
2684 func isDirectAndComparableIface2(v *Value, depth int) bool {
2685 if depth == 0 {
2686 return false
2687 }
2688 switch v.Op {
2689 case OpIMake:
2690 return isDirectAndComparableIface1(v.Args[0], depth-1)
2691 case OpPhi:
2692 for _, a := range v.Args {
2693 if !isDirectAndComparableIface2(a, depth-1) {
2694 return false
2695 }
2696 }
2697 return true
2698 }
2699 return false
2700 }
2701
2702 func bitsAdd64(x, y, carry int64) (r struct{ sum, carry int64 }) {
2703 s, c := bits.Add64(uint64(x), uint64(y), uint64(carry))
2704 r.sum, r.carry = int64(s), int64(c)
2705 return
2706 }
2707
2708 func bitsSub64(x, y, borrow int64) (r struct{ diff, borrow int64 }) {
2709 d, b := bits.Sub64(uint64(x), uint64(y), uint64(borrow))
2710 r.diff, r.borrow = int64(d), int64(b)
2711 return
2712 }
2713
2714 func bitsDiv128u(hi, lo, y int64) (r struct{ quo, rem int64 }) {
2715 q, rem := bits.Div64(uint64(hi), uint64(lo), uint64(y))
2716 r.quo, r.rem = int64(q), int64(rem)
2717 return
2718 }
2719
2720 func bitsMulU64(x, y int64) (r struct{ hi, lo int64 }) {
2721 hi, lo := bits.Mul64(uint64(x), uint64(y))
2722 r.hi, r.lo = int64(hi), int64(lo)
2723 return
2724 }
2725 func bitsMulU32(x, y int32) (r struct{ hi, lo int32 }) {
2726 hi, lo := bits.Mul32(uint32(x), uint32(y))
2727 r.hi, r.lo = int32(hi), int32(lo)
2728 return
2729 }
2730
2731
2732 func flagify(v *Value) bool {
2733 var flagVersion Op
2734 switch v.Op {
2735 case OpAMD64ADDQconst:
2736 flagVersion = OpAMD64ADDQconstflags
2737 case OpAMD64ADDLconst:
2738 flagVersion = OpAMD64ADDLconstflags
2739 default:
2740 base.Fatalf("can't flagify op %s", v.Op)
2741 }
2742 inner := v.copyInto(v.Block)
2743 inner.Op = flagVersion
2744 inner.Type = types.NewTuple(v.Type, types.TypeFlags)
2745 v.reset(OpSelect0)
2746 v.AddArg(inner)
2747 return true
2748 }
2749
2750
2751 type PanicBoundsC struct {
2752 C int64
2753 }
2754
2755
2756 type PanicBoundsCC struct {
2757 Cx int64
2758 Cy int64
2759 }
2760
2761 func (p PanicBoundsC) CanBeAnSSAAux() {
2762 }
2763 func (p PanicBoundsCC) CanBeAnSSAAux() {
2764 }
2765
2766 func auxToPanicBoundsC(i Aux) PanicBoundsC {
2767 return i.(PanicBoundsC)
2768 }
2769 func auxToPanicBoundsCC(i Aux) PanicBoundsCC {
2770 return i.(PanicBoundsCC)
2771 }
2772 func panicBoundsCToAux(p PanicBoundsC) Aux {
2773 return p
2774 }
2775 func panicBoundsCCToAux(p PanicBoundsCC) Aux {
2776 return p
2777 }
2778
2779 func isDictArgSym(sym Sym) bool {
2780 return sym.(*ir.Name).Sym().Name == typecheck.LocalDictName
2781 }
2782
2783
2784
2785
2786 func imakeOfStructMake(v *Value) *Value {
2787 var arg *Value
2788 for _, a := range v.Args[1].Args {
2789 if a.Type.Size() > 0 {
2790 arg = a
2791 break
2792 }
2793 }
2794 return v.Block.NewValue2(v.Pos, OpIMake, v.Type, v.Args[0], arg)
2795 }
2796
2797
2798 func bool2int(x bool) int {
2799 var b int
2800 if x {
2801 b = 1
2802 }
2803 return b
2804 }
2805
2806
2807
2808 func rewriteCondSelectIntoMath(config *Config, op Op, constant int64) bool {
2809 switch config.arch {
2810 case "amd64":
2811
2812
2813 return isPowerOfTwo(uint64(constant))
2814 case "arm64":
2815 switch op {
2816 case OpAdd64, OpAdd32, OpAdd16, OpAdd8:
2817 if constant == 1 {
2818 return false
2819 }
2820 fallthrough
2821 case OpSub64, OpSub32, OpSub16, OpSub8,
2822 OpAnd64, OpAnd32, OpAnd16, OpAnd8,
2823 OpOr64, OpOr32, OpOr16, OpOr8,
2824 OpXor64, OpXor32, OpXor16, OpXor8:
2825
2826 return isPowerOfTwo(uint64(constant))
2827 default:
2828 if constant == 1 {
2829 return true
2830 }
2831 }
2832 default:
2833
2834 return constant == 1
2835 }
2836 return false
2837 }
2838
2839 func addToSub(op Op) Op {
2840 switch op {
2841 case OpAdd64:
2842 return OpSub64
2843 case OpAdd32:
2844 return OpSub32
2845 case OpAdd16:
2846 return OpSub16
2847 case OpAdd8:
2848 return OpSub8
2849 default:
2850 panic(fmt.Sprintf("unexpected op %v", op))
2851 }
2852 }
2853
2854 func modularMultiplicativeInverse(x uint64) (y uint64) {
2855 if x%2 != 1 {
2856 panic("even numbers in a power-of-two modulus do not have a multiplicative inverse")
2857 }
2858
2859 y = x
2860
2861
2862 y *= 2 - x*y
2863 y *= 2 - x*y
2864 y *= 2 - x*y
2865 y *= 2 - x*y
2866 y *= 2 - x*y
2867 return
2868 }
2869
2870 func invertibleBool(op Op) bool {
2871 switch op {
2872 case OpLess64, OpLess32, OpLess16, OpLess8,
2873 OpLeq64, OpLeq32, OpLeq16, OpLeq8,
2874 OpLess64U, OpLess32U, OpLess16U, OpLess8U,
2875 OpLeq64U, OpLeq32U, OpLeq16U, OpLeq8U,
2876 OpEq64, OpEq32, OpEq16, OpEq8,
2877 OpNeq64, OpNeq32, OpNeq16, OpNeq8,
2878 OpNot:
2879 return true
2880 default:
2881 return false
2882 }
2883 }
2884
View as plain text