1
2
3
4
5 package ssa
6
7 import (
8 "encoding/binary"
9 "fmt"
10 "internal/buildcfg"
11 "io"
12 "math"
13 "math/bits"
14 "os"
15 "path/filepath"
16 "strings"
17
18 "cmd/compile/internal/base"
19 "cmd/compile/internal/logopt"
20 "cmd/compile/internal/ssa/ssaop"
21 "cmd/compile/internal/types"
22 "cmd/internal/obj"
23 "cmd/internal/obj/s390x"
24 "cmd/internal/objabi"
25 "cmd/internal/src"
26 )
27
28
29 type Aux interface {
30 CanBeAnSSAAux()
31 }
32
33 func BoolToAuxInt(b bool) int64 {
34 if b {
35 return 1
36 }
37 return 0
38 }
39
40
41
42
43
44
45
46
47
48
49
50
51
52 type FlagConstant uint8
53
54 func IsNewObjectCall(aux Aux) bool {
55 fn := aux.(*AuxCall).Fn
56 return fn != nil && fn.String() == "runtime.newobject"
57 }
58
59 func IsSpecializedMalloc(aux Aux) bool {
60 fn := aux.(*AuxCall).Fn
61 if fn == nil {
62 return false
63 }
64 name := fn.String()
65 return strings.HasPrefix(name, "runtime.mallocgcSmallNoScanSC") ||
66 strings.HasPrefix(name, "runtime.mallocgcSmallScanNoHeaderSC") ||
67 strings.HasPrefix(name, "runtime.mallocgcTinySC")
68 }
69
70
71 type StringAux string
72
73 func StringToAux(s string) Aux {
74 return StringAux(s)
75 }
76
77 func AuxIntToArm64ConditionalParams(i int64) Arm64ConditionalParams {
78 var params Arm64ConditionalParams
79 params.Cond = ssaop.Op(i & 0xffff)
80 i >>= 16
81 params.NzcvVal = uint8(i & 0x0f)
82 i >>= 4
83 params.ConstVal = uint8(i & 0x1f)
84 i >>= 5
85 params.Ind = i == 1
86 return params
87 }
88
89 func LogLargeCopy(funcName string, pos src.XPos, s int64) {
90 if s < 128 {
91 return
92 }
93 if logopt.Enabled() {
94 logopt.LogOpt(pos, "copy", "lower", funcName, fmt.Sprintf("%d bytes", s))
95 }
96 }
97
98
99 type auxMark bool
100
101 var AuxMark auxMark
102
103
104 type PanicBoundsC struct {
105 C int64
106 }
107
108
109 type PanicBoundsCC struct {
110 Cx int64
111 Cy int64
112 }
113
114 func GetPPC64Shiftsh(auxint int64) int64 {
115 return int64(int8(auxint >> 16))
116 }
117
118 func GetPPC64Shiftmb(auxint int64) int64 {
119 return int64(int8(auxint >> 8))
120 }
121
122
123
124 func DecodePPC64RotateMask(sauxint int64) (rotate, mb, me int64, mask uint64) {
125 auxint := uint64(sauxint)
126 rotate = int64((auxint >> 16) & 0xFF)
127 mb = int64((auxint >> 8) & 0xFF)
128 me = int64((auxint >> 0) & 0xFF)
129 nbits := int64((auxint >> 24) & 0xFF)
130 mask = ((1 << uint(nbits-mb)) - 1) ^ ((1 << uint(nbits-me)) - 1)
131 if mb > me {
132 mask = ^mask
133 }
134 if nbits == 32 {
135 mask = uint64(uint32(mask))
136 }
137
138
139
140 me = (me - 1) & (nbits - 1)
141 return
142 }
143
144
145 func DivisionNeedsFixUp(v *Value) bool {
146 return v.AuxInt == 0
147 }
148
149
150
151
152 func ZeroUpper32Bits(x *Value) bool { return zeroUpperBits(x, 32, 3) }
153
154
155
156
157
158
159 func zeroUpperBits(x *Value, bits int64, depth int) bool {
160 if x.Type.IsSigned() && 8*x.Type.Size() <= 64-bits {
161
162
163
164
165
166 return false
167 }
168 if int64(ssaop.OpcodeTable[x.Op].ZeroUpperBits) >= bits {
169 return true
170 }
171 switch x.Op {
172 case ssaop.OpAMD64MOVQconst, ssaop.OpAMD64MOVLconst:
173
174
175
176 return uint64(x.AuxInt)>>(64-bits) == 0
177 case ssaop.OpArg:
178
179
180 return 8*x.Type.Size() == 64-bits && x.Block.Func.Config.Arch == "amd64"
181 case ssaop.OpSelect0, ssaop.OpSelect1:
182
183
184
185
186
187 return int64(ssaop.OpcodeTable[x.Args[0].Op].ZeroUpperBits) >= bits
188 case ssaop.OpPhi:
189
190
191 if depth <= 0 {
192 return false
193 }
194 for i := range x.Args {
195 if !zeroUpperBits(x.Args[i], bits, depth-1) {
196 return false
197 }
198 }
199 return true
200 }
201 return false
202 }
203
204
205 func ZeroUpper48Bits(x *Value) bool { return zeroUpperBits(x, 48, 3) }
206
207
208 func ZeroUpper56Bits(x *Value) bool { return zeroUpperBits(x, 56, 3) }
209
210
211 func IsSamePtr(p1, p2 *Value) bool {
212 if p1 == p2 {
213 return true
214 }
215 if p1.Op != p2.Op {
216 for p1.Op == ssaop.OpOffPtr && p1.AuxInt == 0 {
217 p1 = p1.Args[0]
218 }
219 for p2.Op == ssaop.OpOffPtr && p2.AuxInt == 0 {
220 p2 = p2.Args[0]
221 }
222 if p1 == p2 {
223 return true
224 }
225 if p1.Op != p2.Op {
226 return false
227 }
228 }
229 switch p1.Op {
230 case ssaop.OpOffPtr:
231 return p1.AuxInt == p2.AuxInt && IsSamePtr(p1.Args[0], p2.Args[0])
232 case ssaop.OpAddr, ssaop.OpLocalAddr:
233 return p1.Aux == p2.Aux
234 case ssaop.OpAddPtr:
235 return p1.Args[1] == p2.Args[1] && IsSamePtr(p1.Args[0], p2.Args[0])
236 }
237 return false
238 }
239
240
241
242
243 func Disjoint(p1 *Value, t1 *types.Type, p2 *Value, t2 *types.Type) bool {
244 return Disjoint1(p1, t1.Size(), p2, t2.Size())
245 }
246
247
248
249
250 func Disjoint1(p1 *Value, n1 int64, p2 *Value, n2 int64) bool {
251 if n1 == 0 || n2 == 0 {
252 return true
253 }
254 if p1 == p2 {
255 return false
256 }
257 baseAndOffset := func(ptr *Value) (base *Value, offset int64) {
258 base, offset = ptr, 0
259 for base.Op == ssaop.OpOffPtr {
260 offset += base.AuxInt
261 base = base.Args[0]
262 }
263 if ssaop.OpcodeTable[base.Op].NilCheck {
264 base = base.Args[0]
265 }
266 return base, offset
267 }
268
269
270 if DisjointTypes(p1.Type, p2.Type) {
271 return true
272 }
273
274 p1, off1 := baseAndOffset(p1)
275 p2, off2 := baseAndOffset(p2)
276 if IsSamePtr(p1, p2) {
277 return !Overlap(off1, n1, off2, n2)
278 }
279
280
281
282
283 switch p1.Op {
284 case ssaop.OpAddr, ssaop.OpLocalAddr:
285 if p2.Op == ssaop.OpAddr || p2.Op == ssaop.OpLocalAddr || p2.Op == ssaop.OpSP {
286 return true
287 }
288 return (p2.Op == ssaop.OpArg || p2.Op == ssaop.OpArgIntReg) && p1.Args[0].Op == ssaop.OpSP
289 case ssaop.OpArg, ssaop.OpArgIntReg:
290 if p2.Op == ssaop.OpSP || p2.Op == ssaop.OpLocalAddr {
291 return true
292 }
293 case ssaop.OpSP:
294 return p2.Op == ssaop.OpAddr || p2.Op == ssaop.OpLocalAddr || p2.Op == ssaop.OpArg || p2.Op == ssaop.OpArgIntReg || p2.Op == ssaop.OpSP
295 }
296 return false
297 }
298
299
300
301
302 func DisjointTypes(t1 *types.Type, t2 *types.Type) bool {
303
304 if t1.IsUnsafePtr() || t2.IsUnsafePtr() {
305 return false
306 }
307
308 if !t1.IsPtr() || !t2.IsPtr() {
309
310 return false
311 }
312
313 t1 = t1.Elem()
314 t2 = t2.Elem()
315
316
317
318 if t1.NotInHeap() || t2.NotInHeap() {
319 return false
320 }
321
322 isPtrShaped := func(t *types.Type) bool { return int(t.Size()) == types.PtrSize && t.HasPointers() }
323
324
325 if (isPtrShaped(t1) && !t2.HasPointers()) ||
326 (isPtrShaped(t2) && !t1.HasPointers()) {
327 return true
328 }
329
330 return false
331 }
332
333
334
335 func Overlap(offset1, size1, offset2, size2 int64) bool {
336 if offset1 >= offset2 && offset2+size2 > offset1 {
337 return true
338 }
339 if offset2 >= offset1 && offset1+size1 > offset2 {
340 return true
341 }
342 return false
343 }
344
345
346
347
348
349
350 func isInlinableMemmove(dst, src *Value, sz int64, c *Config) bool {
351
352
353
354
355 switch c.Arch {
356 case "amd64":
357 return sz <= 16 || (sz < 1024 && Disjoint1(dst, sz, src, sz))
358 case "arm64":
359 return sz <= 64 || (sz <= 1024 && Disjoint1(dst, sz, src, sz))
360 case "loong64":
361 return sz <= 16 || (sz <= 64 && Disjoint1(dst, sz, src, sz))
362 case "386":
363 return sz <= 8
364 case "s390x", "ppc64", "ppc64le":
365 return sz <= 8 || Disjoint1(dst, sz, src, sz)
366 case "arm", "mips", "mips64", "mipsle", "mips64le":
367 return sz <= 4
368 }
369 return false
370 }
371
372 func IsInlinableMemmove(dst, src *Value, sz int64, c *Config) bool {
373 return isInlinableMemmove(dst, src, sz, c)
374 }
375
376 func (auxMark) CanBeAnSSAAux() {}
377
378 func (StringAux) CanBeAnSSAAux() {}
379
380
381 func (bfc Arm64BitField) Lsb() int64 {
382 return int64(uint64(bfc) >> 8)
383 }
384
385
386 func (bfc Arm64BitField) Width() int64 {
387 return int64(bfc) & 0xff
388 }
389
390
391 func (condParams Arm64ConditionalParams) Nzcv() int64 {
392 return int64(condParams.NzcvVal)
393 }
394
395
396 func (condParams Arm64ConditionalParams) ConstValue() (int64, bool) {
397 return int64(condParams.ConstVal), condParams.Ind
398 }
399
400
401 func (fc FlagConstant) N() bool {
402 return fc&1 != 0
403 }
404
405
406 func (fc FlagConstant) Z() bool {
407 return fc&2 != 0
408 }
409
410
411
412 func (fc FlagConstant) C() bool {
413 return fc&4 != 0
414 }
415
416
417 func (fc FlagConstant) V() bool {
418 return fc&8 != 0
419 }
420
421 func (fc FlagConstant) Eq() bool {
422 return fc.Z()
423 }
424
425 func (fc FlagConstant) Ne() bool {
426 return !fc.Z()
427 }
428
429 func (fc FlagConstant) Lt() bool {
430 return fc.N() != fc.V()
431 }
432
433 func (fc FlagConstant) Le() bool {
434 return fc.Z() || fc.Lt()
435 }
436
437 func (fc FlagConstant) Gt() bool {
438 return !fc.Z() && fc.Ge()
439 }
440
441 func (fc FlagConstant) Ge() bool {
442 return fc.N() == fc.V()
443 }
444
445 func (fc FlagConstant) Ult() bool {
446 return !fc.C()
447 }
448
449 func (fc FlagConstant) Ule() bool {
450 return fc.Z() || fc.Ult()
451 }
452
453 func (fc FlagConstant) Ugt() bool {
454 return !fc.Z() && fc.Uge()
455 }
456
457 func (fc FlagConstant) Uge() bool {
458 return fc.C()
459 }
460
461 func (fc FlagConstant) LtNoov() bool {
462 return fc.Lt() && !fc.V()
463 }
464
465 func (fc FlagConstant) LeNoov() bool {
466 return fc.Le() && !fc.V()
467 }
468
469 func (fc FlagConstant) GtNoov() bool {
470 return fc.Gt() && !fc.V()
471 }
472
473 func (fc FlagConstant) GeNoov() bool {
474 return fc.Ge() && !fc.V()
475 }
476
477 func (fc FlagConstant) String() string {
478 return fmt.Sprintf("N=%v,Z=%v,C=%v,V=%v", fc.N(), fc.Z(), fc.C(), fc.V())
479 }
480
481 func (p PanicBoundsC) CanBeAnSSAAux() {
482 }
483
484 func (p PanicBoundsCC) CanBeAnSSAAux() {
485 }
486
487
488 func AddFlags32(x, y int32) FlagConstant {
489 var fcb FlagConstantBuilder
490 fcb.Z = x+y == 0
491 fcb.N = x+y < 0
492 fcb.C = uint32(x+y) < uint32(x)
493 fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
494 return fcb.Encode()
495 }
496
497
498
499
500
501
502 func AddFlags64(x, y int64) FlagConstant {
503 var fcb FlagConstantBuilder
504 fcb.Z = x+y == 0
505 fcb.N = x+y < 0
506 fcb.C = uint64(x+y) < uint64(x)
507 fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
508 return fcb.Encode()
509 }
510
511 func Arm64BitFieldToAuxInt(v Arm64BitField) int64 {
512 return int64(v)
513 }
514
515 func Arm64ConditionalParamsToAuxInt(v Arm64ConditionalParams) int64 {
516 if v.Cond&^0xffff != 0 {
517 panic("condition value exceeds 16 bits")
518 }
519
520 var i int64
521 if v.Ind {
522 i = 1 << 25
523 }
524 i |= int64(v.ConstVal) << 20
525 i |= int64(v.NzcvVal) << 16
526 i |= int64(v.Cond)
527 return i
528 }
529
530 type Int64Aux int64
531
532 func (Int64Aux) CanBeAnSSAAux() {}
533
534 func Int64ToAux(v int64) Aux {
535 return Int64Aux(v)
536 }
537
538
539 func ArmBFAuxInt(lsb, width int64) Arm64BitField {
540 if lsb < 0 || lsb > 63 {
541 panic("ARM(64) bit field lsb constant out of range")
542 }
543 if width < 1 || lsb+width > 64 {
544 panic("ARM(64) bit field width constant out of range")
545 }
546 return Arm64BitField(width | lsb<<8)
547 }
548
549 func AuxIntToArm64BitField(i int64) Arm64BitField {
550 return Arm64BitField(i)
551 }
552
553 func AuxIntToBool(i int64) bool {
554 if i == 0 {
555 return false
556 }
557 return true
558 }
559
560 func AuxIntToFlagConstant(x int64) FlagConstant {
561 return FlagConstant(x)
562 }
563
564 func AuxIntToFloat32(i int64) float32 {
565 return float32(math.Float64frombits(uint64(i)))
566 }
567
568 func AuxIntToFloat64(i int64) float64 {
569 return math.Float64frombits(uint64(i))
570 }
571
572 func AuxIntToInt16(i int64) int16 {
573 return int16(i)
574 }
575
576 func AuxIntToInt32(i int64) int32 {
577 return int32(i)
578 }
579
580 func AuxIntToInt64(i int64) int64 {
581 return i
582 }
583
584 func AuxIntToInt8(i int64) int8 {
585 return int8(i)
586 }
587
588 func AuxIntToOp(cc int64) ssaop.Op {
589 return ssaop.Op(cc)
590 }
591
592 func AuxIntToUint64(i int64) uint64 {
593 return uint64(i)
594 }
595
596 func AuxIntToUint8(i int64) uint8 {
597 return uint8(i)
598 }
599
600 func AuxIntToValAndOff(i int64) ValAndOff {
601 return ValAndOff(i)
602 }
603
604 func AuxToCall(i Aux) *AuxCall {
605 return i.(*AuxCall)
606 }
607
608 func AuxToPanicBoundsC(i Aux) PanicBoundsC {
609 return i.(PanicBoundsC)
610 }
611
612 func AuxToPanicBoundsCC(i Aux) PanicBoundsCC {
613 return i.(PanicBoundsCC)
614 }
615
616 func AuxToS390xCCMask(i Aux) s390x.CCMask {
617 return i.(s390x.CCMask)
618 }
619
620 func AuxToS390xRotateParams(i Aux) s390x.RotateParams {
621 return i.(s390x.RotateParams)
622 }
623
624 func AuxToString(i Aux) string {
625 return string(i.(StringAux))
626 }
627
628 func AuxToSym(i Aux) Sym {
629
630 s, _ := i.(Sym)
631 return s
632 }
633
634 func AuxToType(i Aux) *types.Type {
635 return i.(*types.Type)
636 }
637
638
639 func B2i(b bool) int64 {
640 if b {
641 return 1
642 }
643 return 0
644 }
645
646
647 func B2i32(b bool) int32 {
648 if b {
649 return 1
650 }
651 return 0
652 }
653
654 func CallToAux(s *AuxCall) Aux {
655 return s
656 }
657
658
659
660 func CanMergeLoad(target, load *Value) bool {
661 if target.Block.ID != load.Block.ID {
662
663 return false
664 }
665
666
667
668 if load.Uses != 1 {
669 return false
670 }
671
672 mem := load.MemoryArg()
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689 var args []*Value
690 for _, a := range target.Args {
691 if a != load && a.Block.ID == target.Block.ID {
692 args = append(args, a)
693 }
694 }
695
696 f := target.Block.Func
697 visited := f.NewSparseSet(f.NumValues())
698 defer f.RetSparseSet(visited)
699
700
701
702 var memPreds map[*Value]bool
703 for len(args) > 0 {
704 const limit = 2048
705 if visited.Size() >= limit {
706
707 return false
708 }
709 v := args[len(args)-1]
710 args = args[:len(args)-1]
711 if visited.Contains(v.ID) {
712 continue
713 }
714 visited.Add(v.ID)
715 if target.Block.ID != v.Block.ID {
716
717
718 continue
719 }
720 if v.Op == ssaop.OpPhi {
721
722
723
724 continue
725 }
726 if v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
727
728
729 return false
730 }
731 if v.Op.SymEffect()&ssaop.SymAddr != 0 {
732
733
734
735
736
737
738
739
740
741
742
743 return false
744 }
745 if v.Type.IsMemory() {
746 if memPreds == nil {
747
748
749
750 memPreds = make(map[*Value]bool)
751 m := mem
752 const limit = 50
753 for i := 0; i < limit; i++ {
754 if m.Op == ssaop.OpPhi {
755
756
757 break
758 }
759 if m.Block.ID != target.Block.ID {
760 break
761 }
762 if !m.Type.IsMemory() {
763 break
764 }
765 memPreds[m] = true
766 if len(m.Args) == 0 {
767 break
768 }
769 m = m.MemoryArg()
770 }
771 }
772
773
774
775
776
777
778
779
780
781 if memPreds[v] {
782 continue
783 }
784 return false
785 }
786 if len(v.Args) > 0 && v.Args[len(v.Args)-1] == mem {
787
788
789 continue
790 }
791 for _, a := range v.Args {
792 if target.Block.ID == a.Block.ID {
793 args = append(args, a)
794 }
795 }
796 }
797
798 return true
799 }
800
801
802
803
804
805 func CanMergeLoadClobber(target, load, x *Value) bool {
806
807
808
809
810
811
812 switch {
813 case x.Uses == 2 && x.Op == ssaop.OpPhi && len(x.Args) == 2 && (x.Args[0] == target || x.Args[1] == target) && target.Uses == 1:
814
815
816
817
818
819
820
821
822
823 case x.Uses > 1:
824 return false
825 }
826 loopnest := x.Block.Func.Loopnest()
827 if loopnest.Depth(target.Block.ID) > loopnest.Depth(x.Block.ID) {
828 return false
829 }
830 return CanMergeLoad(target, load)
831 }
832
833 func CanMergeSym(x, y Sym) bool {
834 return x == nil || y == nil
835 }
836
837 func CanMulStrengthReduce(config *Config, x int64) bool {
838 _, ok := config.MulRecipes[x]
839 return ok
840 }
841
842 func CanMulStrengthReduce32(config *Config, x int32) bool {
843 _, ok := config.MulRecipes[int64(x)]
844 return ok
845 }
846
847
848
849 func CanonLessThan(x, y *Value) bool {
850 if x.Op != y.Op {
851 return x.Op < y.Op
852 }
853 if !x.Pos.SameFileAndLine(y.Pos) {
854 return x.Pos.Before(y.Pos)
855 }
856 return x.ID < y.ID
857 }
858
859
860
861
862
863
864 func Clobber(vv ...*Value) bool {
865 for _, v := range vv {
866 v.Reset(ssaop.OpInvalid)
867
868 }
869 return true
870 }
871
872
873
874
875 func ClobberIfDead(v *Value) bool {
876 if v.Uses == 1 {
877 v.Reset(ssaop.OpInvalid)
878 }
879
880 return true
881 }
882
883
884
885
886
887
888 func CountRule(v *Value, key string) bool {
889 f := v.Block.Func
890 if f.RuleMatches == nil {
891 f.RuleMatches = make(map[string]int)
892 }
893 f.RuleMatches[key]++
894 return true
895 }
896
897 type DeadValueChoice bool
898
899
900
901
902 func EncodePPC64RotateMask(rotate, mask, nbits int64) int64 {
903 var mb, me, mbn, men int
904
905
906 if mask == 0 || ^mask == 0 || rotate >= nbits {
907 panic(fmt.Sprintf("invalid PPC64 rotate mask: %x %d %d", uint64(mask), rotate, nbits))
908 } else if nbits == 32 {
909 mb = bits.LeadingZeros32(uint32(mask))
910 me = 32 - bits.TrailingZeros32(uint32(mask))
911 mbn = bits.LeadingZeros32(^uint32(mask))
912 men = 32 - bits.TrailingZeros32(^uint32(mask))
913 } else {
914 mb = bits.LeadingZeros64(uint64(mask))
915 me = 64 - bits.TrailingZeros64(uint64(mask))
916 mbn = bits.LeadingZeros64(^uint64(mask))
917 men = 64 - bits.TrailingZeros64(^uint64(mask))
918 }
919
920 if mb == 0 && me == int(nbits) {
921
922 mb, me = men, mbn
923 }
924
925 return int64(me) | int64(mb<<8) | rotate<<16 | nbits<<24
926 }
927
928
929 func FlagArg(v *Value) *Value {
930 if len(v.Args) != 1 || !v.Args[0].Type.IsFlags() {
931 return nil
932 }
933 return v.Args[0]
934 }
935
936 type FlagConstantBuilder struct {
937 N bool
938 Z bool
939 C bool
940 V bool
941 }
942
943 func FlagConstantToAuxInt(x FlagConstant) int64 {
944 return int64(x)
945 }
946
947 func Float32ToAuxInt(f float32) int64 {
948 return int64(math.Float64bits(float64(f)))
949 }
950
951 func Float64ToAuxInt(f float64) int64 {
952 return int64(math.Float64bits(f))
953 }
954
955
956
957
958 func ImakeOfStructMake(v *Value) *Value {
959 var arg *Value
960 for _, a := range v.Args[1].Args {
961 if a.Type.Size() > 0 {
962 arg = a
963 break
964 }
965 }
966 return v.Block.NewValue2(v.Pos, ssaop.OpIMake, v.Type, v.Args[0], arg)
967 }
968
969 func Int16ToAuxInt(i int16) int64 {
970 return int64(i)
971 }
972
973 func Int32ToAuxInt(i int32) int64 {
974 return int64(i)
975 }
976
977 func Int64ToAuxInt(i int64) int64 {
978 return i
979 }
980
981 func Int8ToAuxInt(i int8) int64 {
982 return int64(i)
983 }
984
985
986 func Is12Bit(n int64) bool {
987 return -(1<<11) <= n && n < (1<<11)
988 }
989
990
991 func Is16Bit(n int64) bool {
992 return n == int64(int16(n))
993 }
994
995 func Is16BitInt(t *types.Type) bool {
996 return t.Size() == 2 && t.IsInteger()
997 }
998
999
1000 func Is20Bit(n int64) bool {
1001 return -(1<<19) <= n && n < (1<<19)
1002 }
1003
1004
1005 func Is32Bit(n int64) bool {
1006 return n == int64(int32(n))
1007 }
1008
1009 func Is32BitFloat(t *types.Type) bool {
1010 return t.Size() == 4 && t.IsFloat()
1011 }
1012
1013 func Is32BitInt(t *types.Type) bool {
1014 return t.Size() == 4 && t.IsInteger()
1015 }
1016
1017
1018
1019 func Is64BitFloat(t *types.Type) bool {
1020 return t.Size() == 8 && t.IsFloat()
1021 }
1022
1023 func Is64BitInt(t *types.Type) bool {
1024 return t.Size() == 8 && t.IsInteger()
1025 }
1026
1027 func Is8BitInt(t *types.Type) bool {
1028 return t.Size() == 1 && t.IsInteger()
1029 }
1030
1031
1032 func IsPowerOfTwo[T int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64](n T) bool {
1033 return n > 0 && n&(n-1) == 0
1034 }
1035
1036
1037
1038
1039 func IsPPC64ValidShiftMask(v int64) bool {
1040 if (v != 0) && ((v+1)&v) == 0 {
1041 return true
1042 }
1043 return false
1044 }
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055 func IsPPC64WordRotateMask(v64 int64) bool {
1056
1057 v := uint32(v64)
1058 vp := (v & -v) + v
1059
1060 vn := ^v
1061 vpn := (vn & -vn) + vn
1062 return (v&vp == 0 || vn&vpn == 0) && v != 0
1063 }
1064
1065 func IsPtr(t *types.Type) bool {
1066 return t.IsPtrShaped()
1067 }
1068
1069
1070 func IsSameCall(aux Aux, name string) bool {
1071 fn := aux.(*AuxCall).Fn
1072 return fn != nil && fn.String() == name
1073 }
1074
1075
1076 func IsU32Bit(n int64) bool {
1077 return n == int64(uint32(n))
1078 }
1079
1080
1081
1082 func IsVolatile(v *Value) bool {
1083 for v.Op == ssaop.OpOffPtr || v.Op == ssaop.OpAddPtr || v.Op == ssaop.OpPtrIndex || v.Op == ssaop.OpCopy || v.Op == ssaop.OpSelectNAddr {
1084 v = v.Args[0]
1085 }
1086 return v.Op == ssaop.OpSP
1087 }
1088
1089 const (
1090 LeaveDeadValues DeadValueChoice = false
1091 RemoveDeadValues = true
1092
1093 RepZeroThreshold = 1408
1094 RepMoveThreshold = 1408
1095 )
1096
1097 func Log16(n int16) int64 { return Log16u(uint16(n)) }
1098
1099 func Log16u(n uint16) int64 { return int64(bits.Len16(n)) - 1 }
1100
1101 func Log32(n int32) int64 { return Log32u(uint32(n)) }
1102
1103 func Log32u(n uint32) int64 { return int64(bits.Len32(n)) - 1 }
1104
1105 func Log64(n int64) int64 { return Log64u(uint64(n)) }
1106
1107 func Log64u(n uint64) int64 { return int64(bits.Len64(n)) - 1 }
1108
1109
1110
1111 func Log8u(n uint8) int64 { return int64(bits.Len8(n)) - 1 }
1112
1113
1114
1115 func LogicFlags32(x int32) FlagConstant {
1116 var fcb FlagConstantBuilder
1117 fcb.Z = x == 0
1118 fcb.N = x < 0
1119 return fcb.Encode()
1120 }
1121
1122
1123
1124 func LogicFlags64(x int64) FlagConstant {
1125 var fcb FlagConstantBuilder
1126 fcb.Z = x == 0
1127 fcb.N = x < 0
1128 return fcb.Encode()
1129 }
1130
1131
1132
1133
1134 func LogLargeCopyValue(v *Value, s int64) bool {
1135 if s < 128 {
1136 return true
1137 }
1138 if logopt.Enabled() {
1139 logopt.LogOpt(v.Pos, "copy", "lower", v.Block.Func.Name, fmt.Sprintf("%d bytes", s))
1140 }
1141 return true
1142 }
1143
1144
1145
1146 func LogRule(s string) {
1147 if ruleFile == nil {
1148
1149
1150
1151
1152
1153
1154 w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"),
1155 os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
1156 if err != nil {
1157 panic(err)
1158 }
1159 ruleFile = w
1160 }
1161
1162 fmt.Fprintln(ruleFile, s)
1163 }
1164
1165 func MakeJumpTableSym(b *Block) *obj.LSym {
1166 s := base.Ctxt.Lookup(fmt.Sprintf("%s.jump%d", b.Func.Fe.Func().LSym.Name, b.ID))
1167
1168 s.Set(obj.AttrStatic, true)
1169 return s
1170 }
1171
1172
1173 func MergePPC64AndSrwi(m, s int64) int64 {
1174 mask := MergePPC64RShiftMask(m, s, 32)
1175 if !IsPPC64WordRotateMask(mask) {
1176 return 0
1177 }
1178 return EncodePPC64RotateMask((32-s)&31, mask, 32)
1179 }
1180
1181
1182
1183 func MergePPC64ClrlsldiRlwinm(sld int32, rlw int64) int64 {
1184 r_1, _, _, mask_1 := DecodePPC64RotateMask(rlw)
1185
1186 mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(int64(sld)))
1187
1188
1189 mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(int64(sld)))
1190 r_2 := GetPPC64Shiftsh(int64(sld))
1191 r_3 := (r_1 + r_2) & 31
1192
1193
1194 if !IsPPC64WordRotateMask(int64(mask_3)) || uint64(uint32(mask_3)) != mask_3 {
1195 return 0
1196 }
1197 return EncodePPC64RotateMask(r_3, int64(mask_3), 32)
1198 }
1199
1200
1201
1202 func MergePPC64ClrlsldiSrw(sld, srw int64) int64 {
1203 mask_1 := uint64(0xFFFFFFFF >> uint(srw))
1204
1205 mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(sld))
1206
1207
1208 mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(sld))
1209
1210 r_1 := 32 - srw
1211 r_2 := GetPPC64Shiftsh(sld)
1212 r_3 := (r_1 + r_2) & 31
1213
1214 if uint64(uint32(mask_3)) != mask_3 || mask_3 == 0 {
1215 return 0
1216 }
1217 return EncodePPC64RotateMask(r_3, int64(mask_3), 32)
1218 }
1219
1220
1221
1222 func MergePPC64RShiftMask(m, s, nbits int64) int64 {
1223 smask := uint64((1<<uint(nbits))-1) >> uint(s)
1224 return m & int64(smask)
1225 }
1226
1227
1228
1229 func MergePPC64SldiSrw(sld, srw int64) int64 {
1230 if sld > srw || srw >= 32 {
1231 return 0
1232 }
1233 mask_r := uint32(0xFFFFFFFF) >> uint(srw)
1234 mask_l := uint32(0xFFFFFFFF) >> uint(sld)
1235 mask := (mask_r & mask_l) << uint(sld)
1236 return EncodePPC64RotateMask((32-srw+sld)&31, int64(mask), 32)
1237 }
1238
1239
1240
1241 func MergeSym(x, y Sym) Sym {
1242 if x == nil {
1243 return y
1244 }
1245 if y == nil {
1246 return x
1247 }
1248 panic(fmt.Sprintf("mergeSym with two non-nil syms %v %v", x, y))
1249 }
1250
1251
1252 func MoveSize(align int64, c *Config) int64 {
1253 switch {
1254 case align%8 == 0 && c.PtrSize == 8:
1255 return 8
1256 case align%4 == 0:
1257 return 4
1258 case align%2 == 0:
1259 return 2
1260 }
1261 return 1
1262 }
1263
1264
1265
1266
1267 func MulStrengthReduce(m *Value, v *Value, x int64) *Value {
1268 return v.Block.Func.Config.MulRecipes[x].Build(m, v)
1269 }
1270
1271
1272
1273
1274
1275 func MulStrengthReduce32(m *Value, v *Value, x int32) *Value {
1276 return v.Block.Func.Config.MulRecipes[int64(x)].Build(m, v)
1277 }
1278
1279 func NewPPC64ShiftAuxInt(sh, mb, me, sz int64) int32 {
1280 if sh < 0 || sh >= sz {
1281 panic("PPC64 shift arg sh out of range")
1282 }
1283 if mb < 0 || mb >= sz {
1284 panic("PPC64 shift arg mb out of range")
1285 }
1286 if me < 0 || me >= sz {
1287 panic("PPC64 shift arg me out of range")
1288 }
1289 return int32(sh<<16 | mb<<8 | me)
1290 }
1291
1292
1293
1294
1295
1296
1297
1298 func NoteRule(s string) bool {
1299 fmt.Println(s)
1300 return true
1301 }
1302
1303
1304 func Ntz64(x int64) int { return bits.TrailingZeros64(uint64(x)) }
1305
1306
1307 func OneBit[T int8 | int16 | int32 | int64](x T) bool {
1308 return x&(x-1) == 0 && x != 0
1309 }
1310
1311 func OpToAuxInt(o ssaop.Op) int64 {
1312 return int64(o)
1313 }
1314
1315 func PanicBoundsCCToAux(p PanicBoundsCC) Aux {
1316 return p
1317 }
1318
1319 func PanicBoundsCToAux(p PanicBoundsC) Aux {
1320 return p
1321 }
1322
1323
1324 func Read16(sym Sym, off int64, byteorder binary.ByteOrder) uint16 {
1325 lsym := sym.(*obj.LSym)
1326
1327
1328 var src []byte
1329 if 0 <= off && off < int64(len(lsym.P)) {
1330 src = lsym.P[off:]
1331 }
1332 buf := make([]byte, 2)
1333 copy(buf, src)
1334 return byteorder.Uint16(buf)
1335 }
1336
1337
1338 func Read32(sym Sym, off int64, byteorder binary.ByteOrder) uint32 {
1339 lsym := sym.(*obj.LSym)
1340 var src []byte
1341 if 0 <= off && off < int64(len(lsym.P)) {
1342 src = lsym.P[off:]
1343 }
1344 buf := make([]byte, 4)
1345 copy(buf, src)
1346 return byteorder.Uint32(buf)
1347 }
1348
1349
1350 func Read64(sym Sym, off int64, byteorder binary.ByteOrder) uint64 {
1351 lsym := sym.(*obj.LSym)
1352 var src []byte
1353 if 0 <= off && off < int64(len(lsym.P)) {
1354 src = lsym.P[off:]
1355 }
1356 buf := make([]byte, 8)
1357 copy(buf, src)
1358 return byteorder.Uint64(buf)
1359 }
1360
1361
1362 func Read8(sym Sym, off int64) uint8 {
1363 lsym := sym.(*obj.LSym)
1364 if off >= int64(len(lsym.P)) || off < 0 {
1365
1366
1367
1368
1369 return 0
1370 }
1371 return lsym.P[off]
1372 }
1373
1374 func RewriteStructStore(v *Value) *Value {
1375 b := v.Block
1376 dst := v.Args[0]
1377 x := v.Args[1]
1378 if x.Op != ssaop.OpStructMake {
1379 base.Fatalf("invalid struct store: %v", x)
1380 }
1381 mem := v.Args[2]
1382
1383 t := x.Type
1384 for i, arg := range x.Args {
1385 ft := t.FieldType(i)
1386
1387 addr := b.NewValue1I(v.Pos, ssaop.OpOffPtr, ft.PtrTo(), t.FieldOff(i), dst)
1388 mem = b.NewValue3A(v.Pos, ssaop.OpStore, types.TypeMem, TypeToAux(ft), addr, arg, mem)
1389 }
1390
1391 return mem
1392 }
1393
1394 func S390xCCMaskToAux(c s390x.CCMask) Aux {
1395 return c
1396 }
1397
1398 func S390xRotateParamsToAux(r s390x.RotateParams) Aux {
1399 return r
1400 }
1401
1402
1403
1404
1405 func SetPos(v *Value, pos src.XPos) bool {
1406 v.Pos = pos
1407 return true
1408 }
1409
1410
1411
1412 func ShiftIsBounded(v *Value) bool {
1413 return v.AuxInt != 0
1414 }
1415
1416
1417 func SubFlags32(x, y int32) FlagConstant {
1418 var fcb FlagConstantBuilder
1419 fcb.Z = x-y == 0
1420 fcb.N = x-y < 0
1421 fcb.C = uint32(y) <= uint32(x)
1422 fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
1423 return fcb.Encode()
1424 }
1425
1426
1427 func SubFlags64(x, y int64) FlagConstant {
1428 var fcb FlagConstantBuilder
1429 fcb.Z = x-y == 0
1430 fcb.N = x-y < 0
1431 fcb.C = uint64(y) <= uint64(x)
1432 fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
1433 return fcb.Encode()
1434 }
1435
1436 func SupportsPPC64PCRel() bool {
1437
1438
1439 return buildcfg.GOPPC64 >= 10 && buildcfg.GOOS == "linux"
1440 }
1441
1442
1443 func SymIsRO(sym Sym) bool {
1444 lsym := sym.(*obj.LSym)
1445 return lsym.Type == objabi.SRODATA && len(lsym.R) == 0
1446 }
1447
1448 func SymToAux(s Sym) Aux {
1449 return s
1450 }
1451
1452 func TypeToAux(t *types.Type) Aux {
1453 return t
1454 }
1455
1456 func Uint64ToAuxInt(i uint64) int64 {
1457 return int64(i)
1458 }
1459
1460 func Uint8ToAuxInt(i uint8) int64 {
1461 return int64(int8(i))
1462 }
1463
1464 func ValAndOffToAuxInt(v ValAndOff) int64 {
1465 return int64(v)
1466 }
1467
1468 var ruleFile io.Writer
1469
1470 func (fcs FlagConstantBuilder) Encode() FlagConstant {
1471 var fc FlagConstant
1472 if fcs.N {
1473 fc |= 1
1474 }
1475 if fcs.Z {
1476 fc |= 2
1477 }
1478 if fcs.C {
1479 fc |= 4
1480 }
1481 if fcs.V {
1482 fc |= 8
1483 }
1484 return fc
1485 }
1486
1487 func IsConstZero(v *Value) bool {
1488 switch v.Op {
1489 case ssaop.OpConstNil:
1490 return true
1491 case ssaop.OpConst64, ssaop.OpConst32, ssaop.OpConst16, ssaop.OpConst8, ssaop.OpConstBool, ssaop.OpConst32F, ssaop.OpConst64F:
1492 return v.AuxInt == 0
1493 case ssaop.OpStringMake, ssaop.OpIMake, ssaop.OpComplexMake:
1494 return IsConstZero(v.Args[0]) && IsConstZero(v.Args[1])
1495 case ssaop.OpSliceMake:
1496 return IsConstZero(v.Args[0]) && IsConstZero(v.Args[1]) && IsConstZero(v.Args[2])
1497 case ssaop.OpStringPtr, ssaop.OpStringLen, ssaop.OpSlicePtr, ssaop.OpSliceLen, ssaop.OpSliceCap, ssaop.OpITab, ssaop.OpIData, ssaop.OpComplexReal, ssaop.OpComplexImag:
1498 return IsConstZero(v.Args[0])
1499 }
1500 return false
1501 }
1502
View as plain text