1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 )
10
11 const (
12 InvalidIndex = -1 + iota
13 TrueConditionSuccIndex
14 FalseConditionSuccIndex
15 )
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 func mergeConditionalBranches(f *Func) {
59 if f.Config.arch != "arm64" {
60 return
61 }
62
63
64
65
66
67
68
69
70 blocks := f.postorder()
71
72 for _, block := range blocks {
73
74
75 outerSuccIndex, innerSuccIndex := detectNestedIfPattern(block)
76
77 if outerSuccIndex != InvalidIndex && innerSuccIndex != InvalidIndex {
78 transformNestedIfPattern(block, outerSuccIndex, innerSuccIndex)
79 }
80 }
81 }
82
83
84
85
86 func findFirstNonEmptyPlainBlock(parentBlock *Block, childIndex int) *Block {
87 childBlock := parentBlock.Succs[childIndex].Block()
88 for isEmptyPlainBlock(childBlock) {
89 childBlock = childBlock.Succs[0].Block()
90 }
91 return childBlock
92 }
93
94
95
96
97 func isEmptyPlainBlock(block *Block) bool {
98 return block.Kind == BlockPlain &&
99 len(block.Values) == 0 &&
100 len(block.Preds) == 1
101 }
102
103
104
105
106
107 func removeEmptyPlainBlockChain(parentBlock *Block, childIndex int) *Block {
108 childBlock := parentBlock.Succs[childIndex].Block()
109 for isEmptyPlainBlock(childBlock) {
110 nextBlock := childBlock.Succs[0].Block()
111 removeEmptyPlainBlock(childBlock)
112 childBlock = nextBlock
113 }
114 return childBlock
115 }
116
117
118
119
120 func removeEmptyPlainBlock(block *Block) {
121 prevEdge := block.Preds[0]
122 nextEdge := block.Succs[0]
123
124 prevEdge.b.Succs[prevEdge.i] = nextEdge
125 nextEdge.b.Preds[nextEdge.i] = prevEdge
126
127 block.removePred(0)
128 block.removeSucc(0)
129 block.Reset(BlockInvalid)
130 }
131
132
133
134
135
136
137 func detectNestedIfPattern(outerBlock *Block) (int, int) {
138 if !isIfBlock(outerBlock) {
139
140 return InvalidIndex, InvalidIndex
141 }
142
143
144
145 thenBlock := findFirstNonEmptyPlainBlock(outerBlock, TrueConditionSuccIndex)
146 elseBlock := findFirstNonEmptyPlainBlock(outerBlock, FalseConditionSuccIndex)
147 if thenBlock == elseBlock {
148
149 return InvalidIndex, InvalidIndex
150 }
151
152
153 if thenBlock == outerBlock {
154
155 return detectCyclePattern(outerBlock, FalseConditionSuccIndex)
156 } else if elseBlock == outerBlock {
157
158 return detectCyclePattern(outerBlock, TrueConditionSuccIndex)
159 }
160
161 outerSuccIndex := InvalidIndex
162
163
164 if len(thenBlock.Preds) == 1 &&
165 isIfBlock(thenBlock) &&
166 canValuesBeMoved(thenBlock) {
167
168 outerSuccIndex = TrueConditionSuccIndex
169 } else if len(elseBlock.Preds) == 1 &&
170 isIfBlock(elseBlock) &&
171 canValuesBeMoved(elseBlock) {
172
173 outerSuccIndex = FalseConditionSuccIndex
174 } else {
175
176 return InvalidIndex, InvalidIndex
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193 innerBlock := findFirstNonEmptyPlainBlock(outerBlock, outerSuccIndex)
194 commonBothBlock := findFirstNonEmptyPlainBlock(outerBlock, outerSuccIndex^1)
195 thenBlock = findFirstNonEmptyPlainBlock(innerBlock, TrueConditionSuccIndex)
196 elseBlock = findFirstNonEmptyPlainBlock(innerBlock, FalseConditionSuccIndex)
197
198
199
200 var innerSuccIndex = InvalidIndex
201 switch commonBothBlock {
202 case elseBlock:
203
204
205
206 innerSuccIndex = TrueConditionSuccIndex
207 case thenBlock:
208
209
210
211 innerSuccIndex = FalseConditionSuccIndex
212 default:
213
214 return InvalidIndex, InvalidIndex
215 }
216
217
218
219 outToCommonIndex := outerSuccIndex ^ 1
220 inToCommonIndex := innerSuccIndex ^ 1
221 if !checkSameValuesInPhiNodes(outerBlock, innerBlock, outToCommonIndex, inToCommonIndex) {
222 return InvalidIndex, InvalidIndex
223 }
224
225 return outerSuccIndex, innerSuccIndex
226 }
227
228
229
230
231 func detectCyclePattern(outerBlock *Block, outSuccIndex int) (int, int) {
232 secondCondBlock := findFirstNonEmptyPlainBlock(outerBlock, outSuccIndex)
233
234 if len(secondCondBlock.Preds) != 1 ||
235 len(secondCondBlock.Succs) != 2 ||
236 !isIfBlock(secondCondBlock) ||
237 !canValuesBeMoved(secondCondBlock) {
238 return InvalidIndex, InvalidIndex
239 }
240
241 thenBlock := findFirstNonEmptyPlainBlock(secondCondBlock, TrueConditionSuccIndex)
242 elseBlock := findFirstNonEmptyPlainBlock(secondCondBlock, FalseConditionSuccIndex)
243
244 if thenBlock == elseBlock {
245
246 return InvalidIndex, InvalidIndex
247 }
248
249
250 switch outerBlock {
251 case thenBlock:
252
253 if !checkSameValuesInPhiNodes(outerBlock, thenBlock, outSuccIndex^1, TrueConditionSuccIndex) {
254 return InvalidIndex, InvalidIndex
255 }
256 return outSuccIndex, FalseConditionSuccIndex
257 case elseBlock:
258
259 if !checkSameValuesInPhiNodes(outerBlock, elseBlock, outSuccIndex^1, FalseConditionSuccIndex) {
260 return InvalidIndex, InvalidIndex
261 }
262 return outSuccIndex, TrueConditionSuccIndex
263 default:
264
265 return InvalidIndex, InvalidIndex
266 }
267 }
268
269
270
271
272
273 func checkSameValuesInPhiNodes(outerBlock, innerBlock *Block, outToCommonIndex, inToCommonIndex int) bool {
274
275
276 for isEmptyPlainBlock(outerBlock.Succs[outToCommonIndex].Block()) {
277 outerBlock = outerBlock.Succs[outToCommonIndex].Block()
278 outToCommonIndex = 0
279 }
280
281 for isEmptyPlainBlock(innerBlock.Succs[inToCommonIndex].Block()) {
282 innerBlock = innerBlock.Succs[inToCommonIndex].Block()
283 inToCommonIndex = 0
284 }
285
286
287 if outerBlock.Succs[outToCommonIndex].Block() != innerBlock.Succs[inToCommonIndex].Block() {
288 panic("checkSameValuesInPhiNodes: paths do not lead to the same merge block - invalid CFG pattern for if-conversion")
289 }
290
291 argIndex1 := outerBlock.Succs[outToCommonIndex].Index()
292 argIndex2 := innerBlock.Succs[inToCommonIndex].Index()
293
294 resultBlock := outerBlock.Succs[outToCommonIndex].Block()
295 for _, v := range resultBlock.Values {
296 if v.Op != OpPhi {
297 continue
298 }
299
300
301
302 if v.Args[argIndex1] != v.Args[argIndex2] {
303 return false
304 }
305 }
306
307 return true
308 }
309
310
311
312
313
314 func canValuesBeMoved(b *Block) bool {
315 for _, v := range b.Values {
316 if !canValueBeMoved(v) {
317 return false
318 }
319 }
320 return true
321 }
322
323
324
325
326 func canValueBeMoved(v *Value) bool {
327 if v.Op == OpPhi {
328 return false
329 }
330 if v.Type.IsMemory() {
331 return false
332 }
333 if v.Op.HasSideEffects() {
334 return false
335 }
336 if opcodeTable[v.Op].nilCheck {
337 return false
338 }
339 if v.MemoryArg() != nil {
340 return false
341 }
342 return true
343 }
344
345
346
347
348 func isIfBlock(b *Block) bool {
349 switch b.Kind {
350 case BlockARM64EQ,
351 BlockARM64NE,
352 BlockARM64LT,
353 BlockARM64LE,
354 BlockARM64GT,
355 BlockARM64GE,
356 BlockARM64ULT,
357 BlockARM64ULE,
358 BlockARM64UGT,
359 BlockARM64UGE:
360 return isComparisonOperation(b.Controls[0])
361 case BlockARM64Z,
362 BlockARM64NZ,
363 BlockARM64ZW,
364 BlockARM64NZW:
365 return true
366 default:
367 return false
368 }
369 }
370
371
372
373
374 func isComparisonOperation(value *Value) bool {
375 if value.Uses != 1 {
376
377
378
379 return false
380 }
381
382 switch value.Op {
383 case OpARM64CMP,
384 OpARM64CMPconst,
385 OpARM64CMN,
386 OpARM64CMNconst,
387 OpARM64CMPW,
388 OpARM64CMPWconst,
389 OpARM64CMNW,
390 OpARM64CMNWconst:
391 return true
392 default:
393 return false
394 }
395 }
396
397
398
399
400
401 func transformNestedIfPattern(outerBlock *Block, outSuccIndex, inSuccIndex int) {
402 clearPatternFromEmptyPlainBlocks(outerBlock, outSuccIndex)
403 innerBlock := outerBlock.Succs[outSuccIndex].Block()
404
405
406
407
408
409
410
411
412
413 transformPrimaryComparisonValue(outerBlock)
414 transformDependentComparisonValue(innerBlock)
415 transformToConditionalComparisonValue(outerBlock, outSuccIndex, inSuccIndex)
416 fixComparisonWithConstant(innerBlock, outSuccIndex)
417 setNewControlValue(outerBlock, innerBlock, outSuccIndex, inSuccIndex)
418 moveAllValues(outerBlock, innerBlock)
419 elimNestedBlock(innerBlock, inSuccIndex)
420 }
421
422
423
424 func clearPatternFromEmptyPlainBlocks(outerBlock *Block, outSuccIndex int) {
425 innerBlock := removeEmptyPlainBlockChain(outerBlock, outSuccIndex)
426 removeEmptyPlainBlockChain(outerBlock, outSuccIndex^1)
427
428 removeEmptyPlainBlockChain(innerBlock, TrueConditionSuccIndex)
429 removeEmptyPlainBlockChain(innerBlock, FalseConditionSuccIndex)
430 }
431
432
433
434
435 func moveAllValues(dest, src *Block) {
436 for _, value := range src.Values {
437 value.Block = dest
438 dest.Values = append(dest.Values, value)
439 }
440 src.truncateValues(0)
441 }
442
443
444
445
446 func elimNestedBlock(b *Block, index int) {
447 removedEdge := b.Succs[index^1]
448
449 notBothMetBlock := removedEdge.Block()
450 i := removedEdge.Index()
451
452 b.removeSucc(index ^ 1)
453 notBothMetBlock.removePred(i)
454 for _, v := range notBothMetBlock.Values {
455 if v.Op != OpPhi {
456 continue
457 }
458 notBothMetBlock.removePhiArg(v, i)
459 }
460
461 b.Func.invalidateCFG()
462 b.Reset(BlockPlain)
463 b.Likely = BranchUnknown
464 }
465
466
467
468
469 func setNewControlValue(outerBlock, innerBlock *Block, outSuccIndex, inSuccIndex int) {
470 outerBlock.resetWithControl(innerBlock.Kind, innerBlock.Controls[0])
471 if !isBranchLikelyConsistentWithIndex(outerBlock, outSuccIndex) ||
472 !isBranchLikelyConsistentWithIndex(innerBlock, inSuccIndex) {
473 outerBlock.Likely = BranchUnknown
474 }
475 }
476
477
478
479 func isBranchLikelyConsistentWithIndex(b *Block, index int) bool {
480 if index == TrueConditionSuccIndex && b.Likely == BranchLikely {
481 return true
482 } else if index == FalseConditionSuccIndex && b.Likely == BranchUnlikely {
483 return true
484 }
485 return false
486 }
487
488
489
490
491 func transformPrimaryComparisonValue(block *Block) {
492 switch block.Kind {
493 case BlockARM64Z:
494 arg0 := block.Controls[0]
495 controlValue := block.NewValue1I(arg0.Pos, OpARM64CMPconst, types.TypeFlags, 0, arg0)
496 block.resetWithControl(BlockARM64EQ, controlValue)
497 case BlockARM64NZ:
498 arg0 := block.Controls[0]
499 controlValue := block.NewValue1I(arg0.Pos, OpARM64CMPconst, types.TypeFlags, 0, arg0)
500 block.resetWithControl(BlockARM64NE, controlValue)
501 case BlockARM64ZW:
502 arg0 := block.Controls[0]
503 controlValue := block.NewValue1I(arg0.Pos, OpARM64CMPWconst, types.TypeFlags, 0, arg0)
504 block.resetWithControl(BlockARM64EQ, controlValue)
505 case BlockARM64NZW:
506 arg0 := block.Controls[0]
507 controlValue := block.NewValue1I(arg0.Pos, OpARM64CMPWconst, types.TypeFlags, 0, arg0)
508 block.resetWithControl(BlockARM64NE, controlValue)
509 default:
510 return
511 }
512 }
513
514
515
516
517 func transformDependentComparisonValue(block *Block) {
518 typ := &block.Func.Config.Types
519
520 switch block.Kind {
521 case BlockARM64EQ,
522 BlockARM64NE,
523 BlockARM64LT,
524 BlockARM64LE,
525 BlockARM64GT,
526 BlockARM64GE,
527 BlockARM64ULT,
528 BlockARM64ULE,
529 BlockARM64UGT,
530 BlockARM64UGE:
531 value := block.Controls[0]
532
533 switch value.Op {
534 case OpARM64CMPconst:
535 arg0 := value.Args[0]
536 auxConstant := auxIntToInt64(value.AuxInt)
537 value.reset(OpARM64CMP)
538 constantValue := block.Func.constVal(OpARM64MOVDconst, typ.UInt64, auxConstant, true)
539 value.AddArg2(arg0, constantValue)
540 case OpARM64CMNconst:
541 arg0 := value.Args[0]
542 auxConstant := auxIntToInt64(value.AuxInt)
543 value.reset(OpARM64CMN)
544 constantValue := block.Func.constVal(OpARM64MOVDconst, typ.UInt64, auxConstant, true)
545 value.AddArg2(arg0, constantValue)
546 case OpARM64CMPWconst:
547 arg0 := value.Args[0]
548 auxConstant := auxIntToInt32(value.AuxInt)
549 value.reset(OpARM64CMPW)
550 constantValue := block.Func.constVal(OpARM64MOVDconst, typ.UInt64, int64(auxConstant), true)
551 value.AddArg2(arg0, constantValue)
552 case OpARM64CMNWconst:
553 arg0 := value.Args[0]
554 auxConstant := auxIntToInt32(value.AuxInt)
555 value.reset(OpARM64CMNW)
556 constantValue := block.Func.constVal(OpARM64MOVDconst, typ.UInt64, int64(auxConstant), true)
557 value.AddArg2(arg0, constantValue)
558 default:
559 return
560 }
561 case BlockARM64Z:
562 arg0 := block.Controls[0]
563 arg1 := block.Func.constVal(OpARM64MOVDconst, typ.UInt64, 0, true)
564 comparisonValue := block.NewValue2(arg0.Pos, OpARM64CMP, types.TypeFlags, arg0, arg1)
565 block.resetWithControl(BlockARM64EQ, comparisonValue)
566 case BlockARM64NZ:
567 arg0 := block.Controls[0]
568 arg1 := block.Func.constVal(OpARM64MOVDconst, typ.UInt64, 0, true)
569 comparisonValue := block.NewValue2(arg0.Pos, OpARM64CMP, types.TypeFlags, arg0, arg1)
570 block.resetWithControl(BlockARM64NE, comparisonValue)
571 case BlockARM64ZW:
572 arg0 := block.Controls[0]
573 arg1 := block.Func.constVal(OpARM64MOVDconst, typ.UInt64, 0, true)
574 comparisonValue := block.NewValue2(arg0.Pos, OpARM64CMPW, types.TypeFlags, arg0, arg1)
575 block.resetWithControl(BlockARM64EQ, comparisonValue)
576 case BlockARM64NZW:
577 arg0 := block.Controls[0]
578 arg1 := block.Func.constVal(OpARM64MOVDconst, typ.UInt64, 0, true)
579 comparisonValue := block.NewValue2(arg0.Pos, OpARM64CMPW, types.TypeFlags, arg0, arg1)
580 block.resetWithControl(BlockARM64NE, comparisonValue)
581 default:
582 panic("Wrong block kind")
583 }
584 }
585
586
587
588
589 func fixComparisonWithConstant(block *Block, index int) {
590
591 getImm64 := func(auxInt int64) (uint8, bool) {
592 imm := auxIntToInt64(auxInt)
593 if imm&^0x1f == 0 {
594 return uint8(imm), true
595 }
596 return 0, false
597 }
598
599
600 getImm32 := func(auxInt int64) (uint8, bool) {
601 imm := auxIntToInt32(auxInt)
602 if imm&^0x1f == 0 {
603 return uint8(imm), true
604 }
605 return 0, false
606 }
607
608
609
610
611
612
613 tryConvertToConstForm := func(value *Value, newOp Op, getImm func(int64) (uint8, bool)) {
614 params := value.AuxArm64ConditionalParams()
615 arg0 := value.Args[0]
616 arg1 := value.Args[1]
617 arg2 := value.Args[2]
618
619 if arg1.Op == OpARM64MOVDconst {
620 if imm, ok := getImm(arg1.AuxInt); ok {
621 value.reset(newOp)
622 params.constValue = imm
623 params.ind = true
624 value.AuxInt = arm64ConditionalParamsToAuxInt(params)
625 value.AddArg2(arg0, arg2)
626 return
627 }
628 }
629
630
631 if arg0.Op == OpARM64MOVDconst {
632 if imm, ok := getImm(arg0.AuxInt); ok {
633 value.reset(newOp)
634 invertConditionsInBlock(block, ¶ms, index)
635 params.constValue = imm
636 params.ind = true
637 value.AuxInt = arm64ConditionalParamsToAuxInt(params)
638 value.AddArg2(arg1, arg2)
639 return
640 }
641 }
642 }
643
644
645 controlValue := block.Controls[0]
646 switch controlValue.Op {
647 case OpARM64CCMP:
648 tryConvertToConstForm(controlValue, OpARM64CCMPconst, getImm64)
649 case OpARM64CCMN:
650 tryConvertToConstForm(controlValue, OpARM64CCMNconst, getImm64)
651 case OpARM64CCMPW:
652 tryConvertToConstForm(controlValue, OpARM64CCMPWconst, getImm32)
653 case OpARM64CCMNW:
654 tryConvertToConstForm(controlValue, OpARM64CCMNWconst, getImm32)
655 default:
656 return
657 }
658 }
659
660
661
662
663 func invertConditionsInBlock(block *Block, params *arm64ConditionalParams, index int) {
664 invertKind := invertBlockKind(block.Kind)
665 block.Kind = invertKind
666 if index == FalseConditionSuccIndex {
667 invertKind = negateBlockKind(invertKind)
668 }
669 params.nzcv = nzcvByBlockKind(invertKind)
670 }
671
672
673
674
675
676 func transformToConditionalComparisonValue(outerBlock *Block, outSuccIndex, inSuccIndex int) {
677 innerBlock := outerBlock.Succs[outSuccIndex].Block()
678
679
680 if outSuccIndex != inSuccIndex {
681 outerBlock.Kind = negateBlockKind(outerBlock.Kind)
682 outerBlock.swapSuccessors()
683 outSuccIndex ^= 1
684 }
685
686 outerControl := outerBlock.Controls[0]
687 outerKind := outerBlock.Kind
688
689 innerControl := innerBlock.Controls[0]
690 innerKind := innerBlock.Kind
691
692
693 if outSuccIndex == FalseConditionSuccIndex {
694 outerKind = negateBlockKind(outerKind)
695 innerKind = negateBlockKind(innerKind)
696 }
697
698
699 params := createConditionalParamsByBlockKind(outerKind, innerKind)
700
701 innerControl.AddArg(outerControl)
702 innerControl.Op = transformOpToConditionalComparisonOperation(innerControl.Op)
703 innerControl.AuxInt = arm64ConditionalParamsToAuxInt(params)
704 }
705
706
707
708 func transformOpToConditionalComparisonOperation(op Op) Op {
709 switch op {
710 case OpARM64CMP:
711 return OpARM64CCMP
712 case OpARM64CMN:
713 return OpARM64CCMN
714 case OpARM64CMPconst:
715 return OpARM64CCMPconst
716 case OpARM64CMNconst:
717 return OpARM64CCMNconst
718 case OpARM64CMPW:
719 return OpARM64CCMPW
720 case OpARM64CMNW:
721 return OpARM64CCMNW
722 case OpARM64CMPWconst:
723 return OpARM64CCMPWconst
724 case OpARM64CMNWconst:
725 return OpARM64CCMNWconst
726 default:
727 panic("Incorrect operation")
728 }
729 }
730
731
732
733
734
735
736 func createConditionalParamsByBlockKind(outerKind, innerKind BlockKind) arm64ConditionalParams {
737 cond := condByBlockKind(outerKind)
738 nzcv := nzcvByBlockKind(innerKind)
739 return arm64ConditionalParamsAuxInt(cond, nzcv)
740 }
741
742
743
744 func condByBlockKind(kind BlockKind) Op {
745 switch kind {
746 case BlockARM64EQ:
747 return OpARM64Equal
748 case BlockARM64NE:
749 return OpARM64NotEqual
750 case BlockARM64LT:
751 return OpARM64LessThan
752 case BlockARM64LE:
753 return OpARM64LessEqual
754 case BlockARM64GT:
755 return OpARM64GreaterThan
756 case BlockARM64GE:
757 return OpARM64GreaterEqual
758 case BlockARM64ULT:
759 return OpARM64LessThanU
760 case BlockARM64ULE:
761 return OpARM64LessEqualU
762 case BlockARM64UGT:
763 return OpARM64GreaterThanU
764 case BlockARM64UGE:
765 return OpARM64GreaterEqualU
766 default:
767 panic("Incorrect kind of Block")
768 }
769 }
770
771
772
773
774
775
776
777
778 func nzcvByBlockKind(kind BlockKind) uint8 {
779 switch kind {
780 case BlockARM64EQ:
781
782 return packNZCV(false, false, false, false)
783 case BlockARM64NE:
784
785 return packNZCV(false, true, false, false)
786 case BlockARM64LT:
787
788 return packNZCV(false, false, false, false)
789 case BlockARM64LE:
790
791 return packNZCV(false, false, false, false)
792 case BlockARM64GT:
793
794 return packNZCV(false, true, false, false)
795 case BlockARM64GE:
796
797 return packNZCV(false, false, false, true)
798 case BlockARM64ULT:
799
800 return packNZCV(false, false, true, false)
801 case BlockARM64ULE:
802
803 return packNZCV(false, false, true, false)
804 case BlockARM64UGT:
805
806 return packNZCV(false, false, false, false)
807 case BlockARM64UGE:
808
809 return packNZCV(false, false, false, false)
810 default:
811 panic("Incorrect kind of Block")
812 }
813 }
814
815
816
817 func packNZCV(N, Z, C, V bool) uint8 {
818 var NZCVFlags uint8 = 0
819 if N {
820 NZCVFlags |= 1 << 3
821 }
822 if Z {
823 NZCVFlags |= 1 << 2
824 }
825 if C {
826 NZCVFlags |= 1 << 1
827 }
828 if V {
829 NZCVFlags |= 1
830 }
831 return NZCVFlags
832 }
833
834
835
836 func negateBlockKind(kind BlockKind) BlockKind {
837 switch kind {
838 case BlockARM64EQ:
839 return BlockARM64NE
840 case BlockARM64NE:
841 return BlockARM64EQ
842 case BlockARM64LT:
843 return BlockARM64GE
844 case BlockARM64LE:
845 return BlockARM64GT
846 case BlockARM64GT:
847 return BlockARM64LE
848 case BlockARM64GE:
849 return BlockARM64LT
850 case BlockARM64ULT:
851 return BlockARM64UGE
852 case BlockARM64ULE:
853 return BlockARM64UGT
854 case BlockARM64UGT:
855 return BlockARM64ULE
856 case BlockARM64UGE:
857 return BlockARM64ULT
858 default:
859 panic("Incorrect kind of Block")
860 }
861 }
862
863
864
865 func invertBlockKind(kind BlockKind) BlockKind {
866 switch kind {
867 case BlockARM64EQ:
868 return BlockARM64EQ
869 case BlockARM64NE:
870 return BlockARM64NE
871 case BlockARM64LT:
872 return BlockARM64GT
873 case BlockARM64LE:
874 return BlockARM64GE
875 case BlockARM64GT:
876 return BlockARM64LT
877 case BlockARM64GE:
878 return BlockARM64LE
879 case BlockARM64ULT:
880 return BlockARM64UGT
881 case BlockARM64ULE:
882 return BlockARM64UGE
883 case BlockARM64UGT:
884 return BlockARM64ULT
885 case BlockARM64UGE:
886 return BlockARM64ULE
887 default:
888 panic("Incorrect kind of Block")
889 }
890 }
891
View as plain text