1
2
3
4
5 package ssacompile
6
7 import (
8 "cmp"
9 "slices"
10
11 "cmd/compile/internal/base"
12 "cmd/compile/internal/ssa"
13 "cmd/compile/internal/ssa/ssaop"
14 "cmd/compile/internal/types"
15 "cmd/internal/src"
16 )
17
18
19
20
21
22 func memcombine(f *ssa.Func) {
23 var ptrAlignments []int8
24 if !f.Config.UnalignedOK {
25 ptrAlignments = f.Cache.AllocInt8Slice(f.NumValues())
26 defer f.Cache.FreeInt8Slice(ptrAlignments)
27 computePtrAlignments(f, ptrAlignments)
28 }
29 memcombineLoads(f, ptrAlignments)
30 memcombineStores(f, ptrAlignments)
31 }
32
33 func memcombineLoads(f *ssa.Func, ptrAlignments []int8) {
34
35 mark := f.NewSparseSet(f.NumValues())
36 defer f.RetSparseSet(mark)
37 var order []*ssa.Value
38
39
40 for _, b := range f.Blocks {
41 for _, v := range b.Values {
42 if v.Op == ssaop.OpOr16 || v.Op == ssaop.OpOr32 || v.Op == ssaop.OpOr64 {
43 mark.Add(v.Args[0].ID)
44 mark.Add(v.Args[1].ID)
45 }
46 }
47 }
48 for _, b := range f.Blocks {
49 order = order[:0]
50 for _, v := range b.Values {
51 if v.Op != ssaop.OpOr16 && v.Op != ssaop.OpOr32 && v.Op != ssaop.OpOr64 {
52 continue
53 }
54 if mark.Contains(v.ID) {
55
56 continue
57 }
58
59
60 i := len(order)
61 order = append(order, v)
62 for ; i < len(order); i++ {
63 x := order[i]
64 for j := 0; j < 2; j++ {
65 a := x.Args[j]
66 if a.Op == ssaop.OpOr16 || a.Op == ssaop.OpOr32 || a.Op == ssaop.OpOr64 {
67 order = append(order, a)
68 }
69 }
70 }
71 }
72 for _, v := range order {
73 max := f.Config.RegSize
74 switch v.Op {
75 case ssaop.OpOr64:
76 case ssaop.OpOr32:
77 max = 4
78 case ssaop.OpOr16:
79 max = 2
80 default:
81 continue
82 }
83 for n := max; n > 1; n /= 2 {
84 if combineLoads(v, n, ptrAlignments) {
85 break
86 }
87 }
88 }
89 }
90 }
91
92
93
94
95 type BaseAddress struct {
96 ptr *ssa.Value
97 idx Index
98 }
99
100
101
102
103
104 type Index struct {
105 exp *ssa.Value
106 shift int64
107 }
108
109 func getConst(v *ssa.Value) (int64, bool) {
110 if v.Op == ssaop.OpConst32 || v.Op == ssaop.OpConst64 {
111 return v.AuxInt, true
112 }
113 return 0, false
114 }
115
116 func peelAdd(v *ssa.Value) (exp *ssa.Value, imm int64) {
117 if v == nil {
118 return nil, 0
119 }
120
121 if v.Op == ssaop.OpAdd32 || v.Op == ssaop.OpAdd64 {
122 if imm, ok := getConst(v.Args[0]); ok {
123 return v.Args[1], imm
124 }
125
126 if imm, ok := getConst(v.Args[1]); ok {
127 return v.Args[0], imm
128 }
129 }
130
131 return v, 0
132 }
133
134 func peelShift(v *ssa.Value) (exp *ssa.Value, shift int64) {
135 if v == nil {
136 return nil, 0
137 }
138
139 if v.Op == ssaop.OpLsh64x64 || v.Op == ssaop.OpLsh32x64 || v.Op == ssaop.OpLsh16x64 {
140 if imm, ok := getConst(v.Args[1]); ok {
141 return v.Args[0], imm
142 }
143 }
144 return v, 0
145 }
146
147
148
149
150
151 func splitPtr(ptr *ssa.Value) (BaseAddress, int64) {
152 var idx Index
153 var off int64
154 for {
155 if ptr.Op == ssaop.OpOffPtr {
156 off += ptr.AuxInt
157 ptr = ptr.Args[0]
158 continue
159 }
160
161 if ptr.Op == ssaop.OpAddPtr {
162 if idx.exp != nil {
163
164
165 break
166 }
167
168
169
170
171
172
173
174
175
176
177 idx.exp = ptr.Args[1]
178 ptr = ptr.Args[0]
179
180
181 var offset int64
182 idx.exp, offset = peelAdd(idx.exp)
183 off += offset
184
185
186 idx.exp, idx.shift = peelShift(idx.exp)
187
188
189 var imm int64
190 idx.exp, imm = peelAdd(idx.exp)
191
192 off += imm << idx.shift
193 continue
194 }
195
196 break
197 }
198
199 return BaseAddress{ptr: ptr, idx: idx}, off
200 }
201
202
203
204 func computePtrAlignments(f *ssa.Func, ptrAlignments []int8) {
205 for _, b := range slices.Backward(f.Postorder()) {
206 for _, v := range b.Values {
207 ptrAlignments[v.ID] = int8(valuePtrAlignment(v, ptrAlignments))
208 }
209 }
210 }
211
212
213
214 func ptrAlignment(ptr *ssa.Value, ptrAlignments []int8) int64 {
215 if align := ptrAlignments[ptr.ID]; align > 0 {
216 return int64(align)
217 }
218 return 1
219 }
220
221
222 func valuePtrAlignment(v *ssa.Value, ptrAlignments []int8) int64 {
223
224 if !v.Type.IsPtr() {
225 return 1
226 }
227
228 switch v.Op {
229 case ssaop.OpOffPtr:
230 return offsetAlignment(ptrAlignment(v.Args[0], ptrAlignments), v.AuxInt)
231 case ssaop.OpCopy, ssaop.OpNilCheck:
232 return ptrAlignment(v.Args[0], ptrAlignments)
233 case ssaop.OpAddr, ssaop.OpLocalAddr, ssaop.OpArg, ssaop.OpArgIntReg:
234 return typeAlignment(v.Type.Elem())
235 case ssaop.OpPhi:
236 align := ptrAlignment(v.Args[0], ptrAlignments)
237 for _, arg := range v.Args[1:] {
238 if argAlign := ptrAlignment(arg, ptrAlignments); argAlign < align {
239 align = argAlign
240 }
241 }
242 return align
243 }
244 return 1
245 }
246
247
248
249
250 func typeAlignment(t *types.Type) int64 {
251 switch t.Kind() {
252 case types.TBOOL, types.TINT8, types.TUINT8:
253 return 1
254 case types.TINT16, types.TUINT16:
255 return 2
256 case types.TINT32, types.TUINT32, types.TFLOAT32, types.TCOMPLEX64:
257 return 4
258 case types.TINT64, types.TUINT64, types.TFLOAT64, types.TCOMPLEX128:
259 return 8
260 case types.TINT, types.TUINT, types.TUINTPTR, types.TPTR, types.TUNSAFEPTR, types.TSTRING, types.TSLICE, types.TFUNC, types.TMAP, types.TCHAN:
261 return int64(types.PtrSize)
262 case types.TARRAY:
263 return typeAlignment(t.Elem())
264 case types.TSTRUCT:
265 align := int64(1)
266 for _, f := range t.Fields() {
267 fieldAlign := typeAlignment(f.Type)
268 if fieldAlign > align {
269 align = fieldAlign
270 }
271 }
272 return align
273 }
274 return 1
275 }
276
277 func offsetAlignment(align, off int64) int64 {
278 off &= align - 1
279 if off == 0 {
280 return align
281 }
282 return off & -off
283 }
284
285 func combineLoads(root *ssa.Value, n int64, ptrAlignments []int8) bool {
286 orOp := root.Op
287 var shiftOp ssaop.Op
288 switch orOp {
289 case ssaop.OpOr64:
290 shiftOp = ssaop.OpLsh64x64
291 case ssaop.OpOr32:
292 shiftOp = ssaop.OpLsh32x64
293 case ssaop.OpOr16:
294 shiftOp = ssaop.OpLsh16x64
295 default:
296 return false
297 }
298
299
300 a := make([]*ssa.Value, 0, 8)
301 a = append(a, root)
302 for i := 0; i < len(a) && int64(len(a)) < n; i++ {
303 v := a[i]
304 if v.Uses != 1 && v != root {
305
306 return false
307 }
308 if v.Op == orOp {
309 a[i] = v.Args[0]
310 a = append(a, v.Args[1])
311 i--
312 }
313 }
314 if int64(len(a)) != n {
315 return false
316 }
317
318
319
320 v := a[0]
321 if v.Op == shiftOp {
322 v = v.Args[0]
323 }
324 var extOp ssaop.Op
325 if orOp == ssaop.OpOr64 && (v.Op == ssaop.OpZeroExt8to64 || v.Op == ssaop.OpZeroExt16to64 || v.Op == ssaop.OpZeroExt32to64) ||
326 orOp == ssaop.OpOr32 && (v.Op == ssaop.OpZeroExt8to32 || v.Op == ssaop.OpZeroExt16to32) ||
327 orOp == ssaop.OpOr16 && v.Op == ssaop.OpZeroExt8to16 {
328 extOp = v.Op
329 v = v.Args[0]
330 } else {
331 return false
332 }
333 if v.Op != ssaop.OpLoad {
334 return false
335 }
336 base, _ := splitPtr(v.Args[0])
337 mem := v.Args[1]
338 size := v.Type.Size()
339
340 if root.Block.Func.Config.Arch == "S390X" {
341
342 if base.ptr.Op == ssaop.OpAddr {
343 return false
344 }
345 }
346
347
348 type LoadRecord struct {
349 load *ssa.Value
350 offset int64
351 shift int64
352 }
353 r := make([]LoadRecord, n, 8)
354 for i := int64(0); i < n; i++ {
355 v := a[i]
356 if v.Uses != 1 {
357 return false
358 }
359 shift := int64(0)
360 if v.Op == shiftOp {
361 v, shift = peelShift(v)
362 if v.Uses != 1 {
363 return false
364 }
365 }
366 if v.Op != extOp {
367 return false
368 }
369 load := v.Args[0]
370 if load.Op != ssaop.OpLoad {
371 return false
372 }
373 if load.Uses != 1 {
374 return false
375 }
376 if load.Args[1] != mem {
377 return false
378 }
379 p, off := splitPtr(load.Args[0])
380 if p != base {
381 return false
382 }
383 r[i] = LoadRecord{load: load, offset: off, shift: shift}
384 }
385
386
387 slices.SortFunc(r, func(a, b LoadRecord) int {
388 return cmp.Compare(a.offset, b.offset)
389 })
390
391
392 for i := int64(0); i < n; i++ {
393 if r[i].offset != r[0].offset+i*size {
394 return false
395 }
396 }
397 if !root.Block.Func.Config.UnalignedOK && ptrAlignment(r[0].load.Args[0], ptrAlignments) < n*size {
398 return false
399 }
400
401
402 shift0 := r[0].shift
403 isLittleEndian := true
404 for i := int64(0); i < n; i++ {
405 if r[i].shift != shift0+i*size*8 {
406 isLittleEndian = false
407 break
408 }
409 }
410 isBigEndian := true
411 for i := int64(0); i < n; i++ {
412 if r[i].shift != shift0-i*size*8 {
413 isBigEndian = false
414 break
415 }
416 }
417 if !isLittleEndian && !isBigEndian {
418 return false
419 }
420
421
422
423
424
425 loads := make([]*ssa.Value, n, 8)
426 for i := int64(0); i < n; i++ {
427 loads[i] = r[i].load
428 }
429 loadBlock := mergePoint(root.Block, loads...)
430 if loadBlock == nil {
431 return false
432 }
433
434 pos := src.NoXPos
435 for _, load := range loads {
436 if load.Block == loadBlock {
437 pos = load.Pos
438 break
439 }
440 }
441 if pos == src.NoXPos {
442 return false
443 }
444
445
446 needSwap := isLittleEndian && root.Block.Func.Config.BigEndian ||
447 isBigEndian && !root.Block.Func.Config.BigEndian
448 if needSwap && (size != 1 || !root.Block.Func.Config.HaveByteSwap(n)) {
449 return false
450 }
451
452
453
454
455 v = loadBlock.NewValue2(pos, ssaop.OpLoad, sizeType(n*size), r[0].load.Args[0], mem)
456
457
458 if needSwap {
459 v = byteSwap(loadBlock, pos, v)
460 }
461
462
463 if n*size < root.Type.Size() {
464 v = zeroExtend(loadBlock, pos, v, n*size, root.Type.Size())
465 }
466
467
468 if isLittleEndian && shift0 != 0 {
469 v = leftShift(loadBlock, pos, v, shift0)
470 }
471 if isBigEndian && shift0-(n-1)*size*8 != 0 {
472 v = leftShift(loadBlock, pos, v, shift0-(n-1)*size*8)
473 }
474
475
476 root.Reset(ssaop.OpCopy)
477 root.AddArg(v)
478
479
480
481 for i := int64(0); i < n; i++ {
482 ssa.Clobber(r[i].load)
483 }
484 return true
485 }
486
487 func memcombineStores(f *ssa.Func, ptrAlignments []int8) {
488 mark := f.NewSparseSet(f.NumValues())
489 defer f.RetSparseSet(mark)
490 var order []*ssa.Value
491
492 for _, b := range f.Blocks {
493
494 mark.Clear()
495 for _, v := range b.Values {
496 if v.Op == ssaop.OpStore {
497 mark.Add(v.MemoryArg().ID)
498 }
499 }
500
501
502
503 order = order[:0]
504 for _, v := range b.Values {
505 if v.Op != ssaop.OpStore {
506 continue
507 }
508 if mark.Contains(v.ID) {
509 continue
510 }
511 for {
512 order = append(order, v)
513 v = v.Args[2]
514 if v.Block != b || v.Op != ssaop.OpStore {
515 break
516 }
517 }
518 }
519
520
521 for _, v := range order {
522 if v.Op != ssaop.OpStore {
523 continue
524 }
525
526 size := v.Aux.(*types.Type).Size()
527 if size >= f.Config.RegSize || size == 0 {
528 continue
529 }
530
531 combineStores(v, ptrAlignments)
532 }
533 }
534 }
535
536
537 func combineStores(root *ssa.Value, ptrAlignments []int8) {
538
539 maxRegSize := root.Block.Func.Config.RegSize
540 type StoreRecord struct {
541 store *ssa.Value
542 offset int64
543 size int64
544 }
545 getShiftBase := func(a []StoreRecord) *ssa.Value {
546 x := a[0].store.Args[1]
547 y := a[1].store.Args[1]
548 switch x.Op {
549 case ssaop.OpTrunc64to8, ssaop.OpTrunc64to16, ssaop.OpTrunc64to32, ssaop.OpTrunc32to8, ssaop.OpTrunc32to16, ssaop.OpTrunc16to8:
550 x = x.Args[0]
551 default:
552 return nil
553 }
554 switch y.Op {
555 case ssaop.OpTrunc64to8, ssaop.OpTrunc64to16, ssaop.OpTrunc64to32, ssaop.OpTrunc32to8, ssaop.OpTrunc32to16, ssaop.OpTrunc16to8:
556 y = y.Args[0]
557 default:
558 return nil
559 }
560 var x2 *ssa.Value
561 switch x.Op {
562 case ssaop.OpRsh64Ux64, ssaop.OpRsh32Ux64, ssaop.OpRsh16Ux64:
563 x2 = x.Args[0]
564 default:
565 }
566 var y2 *ssa.Value
567 switch y.Op {
568 case ssaop.OpRsh64Ux64, ssaop.OpRsh32Ux64, ssaop.OpRsh16Ux64:
569 y2 = y.Args[0]
570 default:
571 }
572 if y2 == x {
573
574 return x
575 }
576 if x2 == y {
577
578 return y
579 }
580 if x2 == y2 {
581
582 return x2
583 }
584 return nil
585 }
586 isShiftBase := func(v, base *ssa.Value) bool {
587 val := v.Args[1]
588 switch val.Op {
589 case ssaop.OpTrunc64to8, ssaop.OpTrunc64to16, ssaop.OpTrunc64to32, ssaop.OpTrunc32to8, ssaop.OpTrunc32to16, ssaop.OpTrunc16to8:
590 val = val.Args[0]
591 default:
592 return false
593 }
594 if val == base {
595 return true
596 }
597 switch val.Op {
598 case ssaop.OpRsh64Ux64, ssaop.OpRsh32Ux64, ssaop.OpRsh16Ux64:
599 val = val.Args[0]
600 default:
601 return false
602 }
603 return val == base
604 }
605 shift := func(v, base *ssa.Value) int64 {
606 val := v.Args[1]
607 switch val.Op {
608 case ssaop.OpTrunc64to8, ssaop.OpTrunc64to16, ssaop.OpTrunc64to32, ssaop.OpTrunc32to8, ssaop.OpTrunc32to16, ssaop.OpTrunc16to8:
609 val = val.Args[0]
610 default:
611 return -1
612 }
613 if val == base {
614 return 0
615 }
616 switch val.Op {
617 case ssaop.OpRsh64Ux64, ssaop.OpRsh32Ux64, ssaop.OpRsh16Ux64:
618 val = val.Args[1]
619 default:
620 return -1
621 }
622 if val.Op != ssaop.OpConst64 {
623 return -1
624 }
625 return val.AuxInt
626 }
627
628
629 allMergeable := make([]StoreRecord, 0, 8)
630 rbase, roff := splitPtr(root.Args[0])
631 if root.Block.Func.Config.Arch == "S390X" {
632
633 if rbase.ptr.Op == ssaop.OpAddr {
634 return
635 }
636 }
637 allMergeable = append(allMergeable, StoreRecord{root, roff, root.Aux.(*types.Type).Size()})
638 allMergeableSize := root.Aux.(*types.Type).Size()
639
640
641 for i, x := 1, root.Args[2]; i < 8; i, x = i+1, x.Args[2] {
642 if x.Op != ssaop.OpStore {
643 break
644 }
645 if x.Block != root.Block {
646 break
647 }
648 if x.Uses != 1 {
649 break
650 }
651 xSize := x.Aux.(*types.Type).Size()
652 if xSize == 0 {
653 break
654 }
655 if xSize > maxRegSize-allMergeableSize {
656 break
657 }
658 base, off := splitPtr(x.Args[0])
659 if base != rbase {
660 break
661 }
662 allMergeable = append(allMergeable, StoreRecord{x, off, xSize})
663 allMergeableSize += xSize
664 }
665 if len(allMergeable) <= 1 {
666 return
667 }
668
669 mergeableSet := map[int64][]StoreRecord{}
670 for i, size := 0, int64(0); i < len(allMergeable); i++ {
671 size += allMergeable[i].size
672 for _, bucketSize := range []int64{8, 4, 2} {
673 if size == bucketSize {
674 mergeableSet[size] = slices.Clone(allMergeable[:i+1])
675 break
676 }
677 }
678 }
679 var a []StoreRecord
680 var aTotalSize int64
681 var mem *ssa.Value
682 var pos src.XPos
683
684 for _, s := range []int64{8, 4, 2} {
685 candidate := mergeableSet[s]
686
687
688
689 if len(candidate) >= 2 {
690
691 mem = candidate[len(candidate)-1].store.Args[2]
692
693 pos = candidate[len(candidate)-1].store.Pos
694
695 slices.SortFunc(candidate, func(sr1, sr2 StoreRecord) int {
696 return cmp.Compare(sr1.offset, sr2.offset)
697 })
698
699 sequential := true
700 for i := 1; i < len(candidate); i++ {
701 if candidate[i].offset != candidate[i-1].offset+candidate[i-1].size {
702 sequential = false
703 break
704 }
705 }
706 if sequential {
707 a = candidate
708 aTotalSize = s
709 break
710 }
711 }
712 }
713 if len(a) <= 1 {
714 return
715 }
716
717 ptr := a[0].store.Args[0]
718 if !root.Block.Func.Config.UnalignedOK && ptrAlignment(ptr, ptrAlignments) < aTotalSize {
719 return
720 }
721
722
723 isConst := true
724 for i := range a {
725 switch a[i].store.Args[1].Op {
726 case ssaop.OpConst32, ssaop.OpConst16, ssaop.OpConst8, ssaop.OpConstBool:
727 default:
728 isConst = false
729 }
730 if !isConst {
731 break
732 }
733 }
734 if isConst {
735
736 var c int64
737 for i := range a {
738 mask := int64(1)<<(8*a[i].size) - 1
739 s := 8 * (a[i].offset - a[0].offset)
740 if root.Block.Func.Config.BigEndian {
741 s = (aTotalSize-a[i].size)*8 - s
742 }
743 c |= (a[i].store.Args[1].AuxInt & mask) << s
744 }
745 var cv *ssa.Value
746 switch aTotalSize {
747 case 2:
748 cv = root.Block.Func.ConstInt16(types.Types[types.TUINT16], int16(c))
749 case 4:
750 cv = root.Block.Func.ConstInt32(types.Types[types.TUINT32], int32(c))
751 case 8:
752 cv = root.Block.Func.ConstInt64(types.Types[types.TUINT64], c)
753 }
754
755
756 for i := range a {
757 v := a[i].store
758 if v == root {
759 v.Aux = cv.Type
760 v.Pos = pos
761 v.SetArg(0, ptr)
762 v.SetArg(1, cv)
763 v.SetArg(2, mem)
764 } else {
765 ssa.Clobber(v)
766 v.Type = types.Types[types.TBOOL]
767 }
768 }
769 return
770 }
771
772
773 var loadMem *ssa.Value
774 var loadBase BaseAddress
775 var loadIdx int64
776 for i := range a {
777 load := a[i].store.Args[1]
778 if load.Op != ssaop.OpLoad {
779 loadMem = nil
780 break
781 }
782 if load.Uses != 1 {
783 loadMem = nil
784 break
785 }
786 if load.Type.HasPointers() {
787
788
789
790 loadMem = nil
791 break
792 }
793 mem := load.Args[1]
794 base, idx := splitPtr(load.Args[0])
795 if loadMem == nil {
796
797 loadMem = mem
798 loadBase = base
799 loadIdx = idx
800 continue
801 }
802 if base != loadBase || mem != loadMem {
803 loadMem = nil
804 break
805 }
806 if idx != loadIdx+(a[i].offset-a[0].offset) {
807 loadMem = nil
808 break
809 }
810 }
811 if loadMem != nil {
812
813 load := a[0].store.Args[1]
814 if !root.Block.Func.Config.UnalignedOK && ptrAlignment(load.Args[0], ptrAlignments) < aTotalSize {
815 return
816 }
817 switch aTotalSize {
818 case 2:
819 load.Type = types.Types[types.TUINT16]
820 case 4:
821 load.Type = types.Types[types.TUINT32]
822 case 8:
823 load.Type = types.Types[types.TUINT64]
824 }
825
826
827 for i := range a {
828 v := a[i].store
829 if v == root {
830 v.Aux = load.Type
831 v.Pos = pos
832 v.SetArg(0, ptr)
833 v.SetArg(1, load)
834 v.SetArg(2, mem)
835 } else {
836 ssa.Clobber(v)
837 v.Type = types.Types[types.TBOOL]
838 }
839 }
840 return
841 }
842
843
844 shiftBase := getShiftBase(a)
845 if shiftBase == nil {
846 return
847 }
848 for i := range a {
849 if !isShiftBase(a[i].store, shiftBase) {
850 return
851 }
852 }
853
854
855 isLittleEndian := true
856 shift0 := shift(a[0].store, shiftBase)
857 for i := 1; i < len(a); i++ {
858 if shift(a[i].store, shiftBase) != shift0+(a[i].offset-a[0].offset)*8 {
859 isLittleEndian = false
860 break
861 }
862 }
863 isBigEndian := true
864 shiftedSize := int64(0)
865 for i := 1; i < len(a); i++ {
866 shiftedSize += a[i].size
867 if shift(a[i].store, shiftBase) != shift0-shiftedSize*8 {
868 isBigEndian = false
869 break
870 }
871 }
872 if !isLittleEndian && !isBigEndian {
873 return
874 }
875
876
877 needSwap := isLittleEndian && root.Block.Func.Config.BigEndian ||
878 isBigEndian && !root.Block.Func.Config.BigEndian
879 if needSwap && (int64(len(a)) != aTotalSize || !root.Block.Func.Config.HaveByteSwap(aTotalSize)) {
880 return
881 }
882
883
884
885
886 sv := shiftBase
887 if isLittleEndian && shift0 != 0 {
888 sv = rightShift(root.Block, root.Pos, sv, shift0)
889 }
890 shiftedSize = aTotalSize - a[0].size
891 if isBigEndian && shift0-shiftedSize*8 != 0 {
892 sv = rightShift(root.Block, root.Pos, sv, shift0-shiftedSize*8)
893 }
894 if sv.Type.Size() > aTotalSize {
895 sv = truncate(root.Block, root.Pos, sv, sv.Type.Size(), aTotalSize)
896 }
897 if needSwap {
898 sv = byteSwap(root.Block, root.Pos, sv)
899 }
900
901
902 for i := range a {
903 v := a[i].store
904 if v == root {
905 v.Aux = sv.Type
906 v.Pos = pos
907 v.SetArg(0, ptr)
908 v.SetArg(1, sv)
909 v.SetArg(2, mem)
910 } else {
911 ssa.Clobber(v)
912 v.Type = types.Types[types.TBOOL]
913 }
914 }
915 }
916
917 func sizeType(size int64) *types.Type {
918 switch size {
919 case 8:
920 return types.Types[types.TUINT64]
921 case 4:
922 return types.Types[types.TUINT32]
923 case 2:
924 return types.Types[types.TUINT16]
925 default:
926 base.Fatalf("bad size %d\n", size)
927 return nil
928 }
929 }
930
931 func truncate(b *ssa.Block, pos src.XPos, v *ssa.Value, from, to int64) *ssa.Value {
932 switch from*10 + to {
933 case 82:
934 return b.NewValue1(pos, ssaop.OpTrunc64to16, types.Types[types.TUINT16], v)
935 case 84:
936 return b.NewValue1(pos, ssaop.OpTrunc64to32, types.Types[types.TUINT32], v)
937 case 42:
938 return b.NewValue1(pos, ssaop.OpTrunc32to16, types.Types[types.TUINT16], v)
939 default:
940 base.Fatalf("bad sizes %d %d\n", from, to)
941 return nil
942 }
943 }
944 func zeroExtend(b *ssa.Block, pos src.XPos, v *ssa.Value, from, to int64) *ssa.Value {
945 switch from*10 + to {
946 case 24:
947 return b.NewValue1(pos, ssaop.OpZeroExt16to32, types.Types[types.TUINT32], v)
948 case 28:
949 return b.NewValue1(pos, ssaop.OpZeroExt16to64, types.Types[types.TUINT64], v)
950 case 48:
951 return b.NewValue1(pos, ssaop.OpZeroExt32to64, types.Types[types.TUINT64], v)
952 default:
953 base.Fatalf("bad sizes %d %d\n", from, to)
954 return nil
955 }
956 }
957
958 func leftShift(b *ssa.Block, pos src.XPos, v *ssa.Value, shift int64) *ssa.Value {
959 s := b.Func.ConstInt64(types.Types[types.TUINT64], shift)
960 size := v.Type.Size()
961 switch size {
962 case 8:
963 return b.NewValue2(pos, ssaop.OpLsh64x64, v.Type, v, s)
964 case 4:
965 return b.NewValue2(pos, ssaop.OpLsh32x64, v.Type, v, s)
966 case 2:
967 return b.NewValue2(pos, ssaop.OpLsh16x64, v.Type, v, s)
968 default:
969 base.Fatalf("bad size %d\n", size)
970 return nil
971 }
972 }
973 func rightShift(b *ssa.Block, pos src.XPos, v *ssa.Value, shift int64) *ssa.Value {
974 s := b.Func.ConstInt64(types.Types[types.TUINT64], shift)
975 size := v.Type.Size()
976 switch size {
977 case 8:
978 return b.NewValue2(pos, ssaop.OpRsh64Ux64, v.Type, v, s)
979 case 4:
980 return b.NewValue2(pos, ssaop.OpRsh32Ux64, v.Type, v, s)
981 case 2:
982 return b.NewValue2(pos, ssaop.OpRsh16Ux64, v.Type, v, s)
983 default:
984 base.Fatalf("bad size %d\n", size)
985 return nil
986 }
987 }
988 func byteSwap(b *ssa.Block, pos src.XPos, v *ssa.Value) *ssa.Value {
989 switch v.Type.Size() {
990 case 8:
991 return b.NewValue1(pos, ssaop.OpBswap64, v.Type, v)
992 case 4:
993 return b.NewValue1(pos, ssaop.OpBswap32, v.Type, v)
994 case 2:
995 return b.NewValue1(pos, ssaop.OpBswap16, v.Type, v)
996
997 default:
998 v.Fatalf("bad size %d\n", v.Type.Size())
999 return nil
1000 }
1001 }
1002
View as plain text